Agile Database Development 2ed

Agile Database Development 2ed

Hi, I'm David. I like to write database apps. Just as much as I like to write web apps. (Maybe more!) How? Not by relying on bolted-on, half-baked database integration tools like migrations, I'll tell you that!. Instead, I make extensive use of best-of-breed tools for source control ([Git](http://git-scm.org/)), database unit testing ([pgTAP](http://pgtap.org/)), and database change management and deployment ([Sqitch](http://sqitch.org/). If you'd like to get as much pleasure out of database development as you do application development, join me for this tutorial. We'll develop a sample application using the processes and tools I've come to depend on, and you'll find out whether they might work for you. Either way, I promise it will at least be an amusing use of your time.

[Originally presented at PGCon 2013](http://www.pgcon.org/2013/schedule/events/615.en.html), revised January 2014.

397f829eea921e02e35c37c22f9e6d3b?s=128

David E. Wheeler

January 09, 2014
Tweet

Transcript

  1. Instructions https:/ /github.com/theory/agile-flipr

  2. Agile Database Development David E. Wheeler ! ! ! January

    2014 Portland Text: Attribution-Noncommercial-Share Alike 3.0 United States: http:/ /creativecommons.org/licenses/by-nc-sa/3.0/us/ Images licensed independently and © Their respective owners. iovation
  3. Agile Database Development David E. Wheeler ! ! ! January

    2014 Portland Text: Attribution-Noncommercial-Share Alike 3.0 United States: http:/ /creativecommons.org/licenses/by-nc-sa/3.0/us/ Images licensed independently and © Their respective owners. ✘ iovation
  4. David E. Wheeler ! ! ! January 2014 Portland Text:

    Attribution-Noncommercial-Share Alike 3.0 United States: http:/ /creativecommons.org/licenses/by-nc-sa/3.0/us/ Images licensed independently and © Their respective owners.
  5. David E. Wheeler ! ! ! January 2014 Portland License:

    Attribution-Noncommercial-Share Alike 3.0 United States: http:/ /creativecommons.org/licenses/by-nc-sa/3.0/us/
  6. Build My VC-Funded App for Me for Free David E.

    Wheeler ! ! ! January 2014 Portland License: Attribution-Noncommercial-Share Alike 3.0 United States: http:/ /creativecommons.org/licenses/by-nc-sa/3.0/us/ ✔ CEO, Data Architect Agile Assholes, Inc.
  7. This is Genius

  8. This is Genius I had this idea

  9. This is Genius I had this idea Social networking is

    HAWT
  10. This is Genius I had this idea Social networking is

    HAWT Has been for waaaay too long
  11. This is Genius I had this idea Social networking is

    HAWT Has been for waaaay too long The backlash is long overdue
  12. This is Genius I had this idea Social networking is

    HAWT Has been for waaaay too long The backlash is long overdue Getting ahead of the curve
  13. This is Genius I had this idea Social networking is

    HAWT Has been for waaaay too long The backlash is long overdue Getting ahead of the curve Introducing…
  14. http:/ /flic.kr/p/8j5gG8 © 2010 Strongrrl. All rights reserved. Used with

    permission.
  15. antisocial network http:/ /flic.kr/p/8j5gG8 © 2010 Strongrrl. All rights reserved.

    Used with permission.
  16. How it Works antisocial network

  17. How it Works Microblogging platform antisocial network

  18. How it Works Microblogging platform Everyone follows you antisocial network

  19. How it Works Microblogging platform Everyone follows you New users

    follow everyone antisocial network
  20. How it Works Microblogging platform Everyone follows you New users

    follow everyone Goal: Alienate your followers antisocial network
  21. How it Works Microblogging platform Everyone follows you New users

    follow everyone Goal: Alienate your followers Get them to unfollow you antisocial network
  22. How it Works Microblogging platform Everyone follows you New users

    follow everyone Goal: Alienate your followers Get them to unfollow you Leaderboard: Those with fewest followers antisocial network
  23. Your Task antisocial network

  24. Your Task Create the database antisocial network

  25. Your Task Create the database Use agile development to make

    it right antisocial network
  26. Your Task Create the database Use agile development to make

    it right Contribute to VC-funded Corp antisocial network
  27. Your Task Create the database Use agile development to make

    it right Contribute to VC-funded Corp Profit! antisocial network
  28. Your Task Create the database Use agile development to make

    it right Contribute to VC-funded Corp Profit! For VC-funded Corp antisocial network
  29. http:/ /flic.kr/p/2honiQ © 2007 James Duncan Davidson. All rights reserved.

    Used with permission.
  30. But first… antisocial network

  31. NDA antisocial network

  32. Job Requirements antisocial network

  33. Job Requirements PostgreSQL Should be installed antisocial network

  34. Job Requirements PostgreSQL Should be installed Git Should be installed

    antisocial network
  35. Job Requirements PostgreSQL Should be installed Git Should be installed

    Sqitch sudo yum install sqitch-pg antisocial network
  36. Job Requirements PostgreSQL Should be installed Git Should be installed

    Sqitch sudo yum install sqitch-pg pgTAP sudo yum install pgtap92 antisocial network
  37. Job Requirements PostgreSQL Should be installed Git Should be installed

    Sqitch sudo yum install sqitch-pg pgTAP sudo yum install pgtap92 pg_prove yum install perl-TAP-Parser-SourceHandler-pgTAP antisocial network
  38. We good? antisocial network

  39. Let’s do this thang. antisocial network

  40. > Who Am I?

  41. git config -­‐-­‐global user.name 'David  E.  Wheeler' > > Who

    Am I?
  42. git config -­‐-­‐global user.name 'David  E.  Wheeler' > > Who

    Am I?
  43. git config -­‐-­‐global user.name 'David  E.  Wheeler' > git config

    -­‐-­‐global user.email david@justatheory.com > > Who Am I?
  44. git config -­‐-­‐global user.name 'David  E.  Wheeler' > git config

    -­‐-­‐global user.email david@justatheory.com > > Who Am I?
  45. git config -­‐-­‐global user.name 'David  E.  Wheeler' > git config

    -­‐-­‐global user.email david@justatheory.com > > Who Am I? Please use your own name and email.
  46. git config -­‐-­‐global user.name 'David  E.  Wheeler' > git config

    -­‐-­‐global user.email david@justatheory.com > > Who Am I? emacs ~/.gitconfig >
  47. ~/.gitconfig ~/ .gitconfig [user]       name  =  David

     E.  Wheeler         email  =  david@justatheory.com
  48. ~/.gitconfig ~/ .gitconfig [user]       name  =  David

     E.  Wheeler         email  =  david@justatheory.com Good for all projects
  49. Create a Remote

  50. Create a Remote Create Git project in Stash

  51. Create a Remote Create Git project in Stash Or Git

    or BitBucket
  52. Create a Remote Create Git project in Stash Or Git

    or BitBucket Wherever you like
  53. Create a Remote Create Git project in Stash Or Git

    or BitBucket Wherever you like Record remote URL
  54. Gitiup >

  55. mkdir flipr-­‐db > cd flipr-­‐db > git init Initialized empty

    Git repository in flipr-­‐db/.git/ > Gitiup >
  56. mkdir flipr-­‐db > cd flipr-­‐db > git init Initialized empty

    Git repository in flipr-­‐db/.git/ > Gitiup >
  57. mkdir flipr-­‐db > cd flipr-­‐db > git init Initialized empty

    Git repository in flipr-­‐db/.git/ > Gitiup > echo Flipr Database Project > README.md >
  58. mkdir flipr-­‐db > cd flipr-­‐db > git init Initialized empty

    Git repository in flipr-­‐db/.git/ > Gitiup > echo Flipr Database Project > README.md > git add . >
  59. mkdir flipr-­‐db > cd flipr-­‐db > git init Initialized empty

    Git repository in flipr-­‐db/.git/ > Gitiup > echo Flipr Database Project > README.md > git add . > git commit -­‐m 'Initialize repo, add README.' [master (root-­‐commit) 9531fab] Initialize repo, add README. 1 file changed, 1 insertion(+) create mode 100644 README.md >
  60. mkdir flipr-­‐db > cd flipr-­‐db > git init Initialized empty

    Git repository in flipr-­‐db/.git/ > Gitiup > echo Flipr Database Project > README.md > git add . > git commit -­‐m 'Initialize repo, add README.' [master (root-­‐commit) 9531fab] Initialize repo, add README. 1 file changed, 1 insertion(+) create mode 100644 README.md >
  61. mkdir flipr-­‐db > cd flipr-­‐db > git init Initialized empty

    Git repository in flipr-­‐db/.git/ > Gitiup > echo Flipr Database Project > README.md > git add . > git commit -­‐m 'Initialize repo, add README.' [master (root-­‐commit) 9531fab] Initialize repo, add README. 1 file changed, 1 insertion(+) create mode 100644 README.md > We have a Git repo.
  62. > Origin

  63. git remote add origin ssh://git@source.iovationnp.com:7999 > > Origin

  64. git push -­‐u origin master Counting objects: 3, done. Writing

    objects: 100% (3/3), 260 bytes, done. Total 3 (delta 0), reused 0 (delta 0) To https://github.com/theory/agile-­‐flipr.git * [new branch] master -­‐> master Branch master set up to track remote branch master from orig > git remote add origin ssh://git@source.iovationnp.com:7999 > > Origin
  65. git push -­‐u origin master Counting objects: 3, done. Writing

    objects: 100% (3/3), 260 bytes, done. Total 3 (delta 0), reused 0 (delta 0) To https://github.com/theory/agile-­‐flipr.git * [new branch] master -­‐> master Branch master set up to track remote branch master from orig > git remote add origin ssh://git@source.iovationnp.com:7999 > > Origin
  66. git push -­‐u origin master Counting objects: 3, done. Writing

    objects: 100% (3/3), 260 bytes, done. Total 3 (delta 0), reused 0 (delta 0) To https://github.com/theory/agile-­‐flipr.git * [new branch] master -­‐> master Branch master set up to track remote branch master from orig > git remote add origin ssh://git@source.iovationnp.com:7999 > > Origin
  67. git push -­‐u origin master Counting objects: 3, done. Writing

    objects: 100% (3/3), 260 bytes, done. Total 3 (delta 0), reused 0 (delta 0) To https://github.com/theory/agile-­‐flipr.git * [new branch] master -­‐> master Branch master set up to track remote branch master from orig > git remote add origin ssh://git@source.iovationnp.com:7999 > > Origin
  68. Swimming Upstream >

  69. git remote add upstream \ https://github.com/theory/agile-­‐flipr.git > Swimming Upstream >

  70. git remote add upstream \ https://github.com/theory/agile-­‐flipr.git > Swimming Upstream >

    git fetch upstream From https://github.com/theory/agile-­‐flipr * [new branch] change_pass -­‐> upstream/change_pass * [new branch] flips -­‐> upstream/flips * [new branch] master -­‐> upstream/master * [new branch] userfuncs -­‐> upstream/userfuncs * [new branch] users -­‐> upstream/users From https://github.com/theory/agile-­‐flipr * [new tag] insert_user2 -­‐> insert_user2 * [new tag] reltag -­‐> reltag * [new tag] v1.0.0-­‐r1 -­‐> v1.0.0-­‐r1 >
  71. git remote add upstream \ https://github.com/theory/agile-­‐flipr.git > Swimming Upstream >

    git fetch upstream From https://github.com/theory/agile-­‐flipr * [new branch] change_pass -­‐> upstream/change_pass * [new branch] flips -­‐> upstream/flips * [new branch] master -­‐> upstream/master * [new branch] userfuncs -­‐> upstream/userfuncs * [new branch] users -­‐> upstream/users From https://github.com/theory/agile-­‐flipr * [new tag] insert_user2 -­‐> insert_user2 * [new tag] reltag -­‐> reltag * [new tag] v1.0.0-­‐r1 -­‐> v1.0.0-­‐r1 > For resetting later
  72. Git? antisocial network

  73. Git? Manage tree of files over time antisocial network

  74. Git? Manage tree of files over time Distributed development antisocial

    network
  75. Git? Manage tree of files over time Distributed development Commit

    changes locally antisocial network
  76. Git? Manage tree of files over time Distributed development Commit

    changes locally Merge to remote (origin, upstream) antisocial network
  77. Git? Manage tree of files over time Distributed development Commit

    changes locally Merge to remote (origin, upstream) Speedy, responsive antisocial network
  78. Git? Manage tree of files over time Distributed development Commit

    changes locally Merge to remote (origin, upstream) Speedy, responsive Flexible, robust antisocial network
  79. Why Git? antisocial network

  80. Why Git? Anyone can clone antisocial network

  81. Why Git? Anyone can clone Complete repository copy antisocial network

  82. Why Git? Anyone can clone Complete repository copy Cheap branching

    antisocial network
  83. Why Git? Anyone can clone Complete repository copy Cheap branching

    Make and test local changes antisocial network
  84. Why Git? Anyone can clone Complete repository copy Cheap branching

    Make and test local changes Submit patches, pull requests antisocial network
  85. Why Git? Anyone can clone Complete repository copy Cheap branching

    Make and test local changes Submit patches, pull requests Pull from upstream antisocial network
  86. PiSHA1 antisocial network

  87. PiSHA1 SHA1 ID for every object antisocial network

  88. PiSHA1 SHA1 ID for every object commit, tag, tree, blob

    antisocial network
  89. PiSHA1 SHA1 ID for every object commit, tag, tree, blob

    Hashed commit text includes: antisocial network
  90. PiSHA1 SHA1 ID for every object commit, tag, tree, blob

    Hashed commit text includes: tree ID antisocial network
  91. PiSHA1 SHA1 ID for every object commit, tag, tree, blob

    Hashed commit text includes: tree ID parent ID antisocial network
  92. PiSHA1 SHA1 ID for every object commit, tag, tree, blob

    Hashed commit text includes: tree ID parent ID author antisocial network
  93. PiSHA1 SHA1 ID for every object commit, tag, tree, blob

    Hashed commit text includes: tree ID parent ID author committer antisocial network
  94. PiSHA1 SHA1 ID for every object commit, tag, tree, blob

    Hashed commit text includes: tree ID parent ID author committer message antisocial network
  95. > Making a hash of it

  96. > git cat-­‐file commit HEAD tree 8b0955fd015782a26953e20d41db5fadbb347c14 parent 0f38581c4d19313d910c2080b3470cae07f3694e author

    David Wheeler <david@justatheory.com> 1367971872 -­‐0700 committer David Wheeler <david@justatheory.com> 1367971872 -­‐0700 Get through "Ship it!". > Making a hash of it
  97. > git cat-­‐file commit HEAD tree 8b0955fd015782a26953e20d41db5fadbb347c14 parent 0f38581c4d19313d910c2080b3470cae07f3694e author

    David Wheeler <david@justatheory.com> 1367971872 -­‐0700 committer David Wheeler <david@justatheory.com> 1367971872 -­‐0700 Get through "Ship it!". > Making a hash of it
  98. > git cat-­‐file commit HEAD tree 8b0955fd015782a26953e20d41db5fadbb347c14 parent 0f38581c4d19313d910c2080b3470cae07f3694e author

    David Wheeler <david@justatheory.com> 1367971872 -­‐0700 committer David Wheeler <david@justatheory.com> 1367971872 -­‐0700 Get through "Ship it!". > Making a hash of it
  99. > git cat-­‐file commit HEAD tree 8b0955fd015782a26953e20d41db5fadbb347c14 parent 0f38581c4d19313d910c2080b3470cae07f3694e author

    David Wheeler <david@justatheory.com> 1367971872 -­‐0700 committer David Wheeler <david@justatheory.com> 1367971872 -­‐0700 Get through "Ship it!". > Making a hash of it
  100. > git cat-­‐file commit HEAD tree 8b0955fd015782a26953e20d41db5fadbb347c14 parent 0f38581c4d19313d910c2080b3470cae07f3694e author

    David Wheeler <david@justatheory.com> 1367971872 -­‐0700 committer David Wheeler <david@justatheory.com> 1367971872 -­‐0700 Get through "Ship it!". > Making a hash of it
  101. > git cat-­‐file commit HEAD tree 8b0955fd015782a26953e20d41db5fadbb347c14 parent 0f38581c4d19313d910c2080b3470cae07f3694e author

    David Wheeler <david@justatheory.com> 1367971872 -­‐0700 committer David Wheeler <david@justatheory.com> 1367971872 -­‐0700 Get through "Ship it!". > Making a hash of it
  102. SHAzam! antisocial network

  103. SHAzam! Each commit (except first) includes parent antisocial network

  104. SHAzam! Each commit (except first) includes parent Can trace from

    any commit to the beginning antisocial network
  105. SHAzam! Each commit (except first) includes parent Can trace from

    any commit to the beginning Tampering (corruption) detectable antisocial network
  106. SHAzam! Each commit (except first) includes parent Can trace from

    any commit to the beginning Tampering (corruption) detectable Because the hash will be wrong antisocial network
  107. SHAzam! Each commit (except first) includes parent Can trace from

    any commit to the beginning Tampering (corruption) detectable Because the hash will be wrong Linus Torvalds’s “greatest invention” http:/ /perl.plover.com/yak/git/ antisocial network
  108. antisocial network Your Turn

  109. antisocial network Your Turn Configure Git

  110. antisocial network Your Turn Configure Git Initialize repository

  111. antisocial network Your Turn Configure Git Initialize repository Add origin

    remote
  112. antisocial network Your Turn Configure Git Initialize repository Add origin

    remote Add upstream remote
  113. antisocial network Your Turn Configure Git Initialize repository Add origin

    remote Add upstream remote https:/ /github.com/ theory/agile-flipr.git
  114. Who am I again? >

  115.    sqitch  config  -­‐-­‐user  user.name  'David  E.  Wheeler' > Who

    am I again? >
  116.    sqitch  config  -­‐-­‐user  user.name  'David  E.  Wheeler' > Who

    am I again? >
  117.    sqitch  config  -­‐-­‐user  user.name  'David  E.  Wheeler' >  

     sqitch  config  -­‐-­‐user  user.email  david@justatheory.com > Who am I again? >
  118.    sqitch  config  -­‐-­‐user  user.name  'David  E.  Wheeler' >  

     sqitch  config  -­‐-­‐user  user.email  david@justatheory.com > > Who am I again? >    emacs  ~/.sqitch/sqitch.conf >
  119. ~/.sqitch/sqitc ~/ .sqitch/sqitch.conf [user]       name  =  David

     E.  Wheeler         email  =  david@justatheory.com  
  120. ~/.sqitch/sqitc ~/ .sqitch/sqitch.conf [user]       name  =  David

     E.  Wheeler         email  =  david@justatheory.com   Good for all projects
  121. > Scratch that Sqitch

  122. > sqitch -­‐-­‐engine pg init flipr \ -­‐-­‐uri https://github.com/theory/agile-­‐flipr Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch
  123. > sqitch -­‐-­‐engine pg init flipr \ -­‐-­‐uri https://github.com/theory/agile-­‐flipr Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch
  124. > sqitch -­‐-­‐engine pg init flipr \ -­‐-­‐uri https://github.com/theory/agile-­‐flipr Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch Use remote URL
  125. > sqitch -­‐-­‐engine pg init flipr \ -­‐-­‐uri https://github.com/theory/agile-­‐flipr Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch
  126. > sqitch -­‐-­‐engine pg init flipr \ -­‐-­‐uri https://github.com/theory/agile-­‐flipr Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch
  127. > sqitch -­‐-­‐engine pg init flipr \ -­‐-­‐uri https://github.com/theory/agile-­‐flipr Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch
  128. > sqitch -­‐-­‐engine pg init flipr \ -­‐-­‐uri https://github.com/theory/agile-­‐flipr Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch
  129. > sqitch -­‐-­‐engine pg init flipr \ -­‐-­‐uri https://github.com/theory/agile-­‐flipr Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch
  130. > sqitch -­‐-­‐engine pg init flipr \ -­‐-­‐uri https://github.com/theory/agile-­‐flipr Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch    emacs  sqitch.conf >
  131. sqitch.conf sqitch.conf [core]     engine  =  pg    

    #  plan_file  =  sqitch.plan     #  top_dir  =  .     #  deploy_dir  =  deploy     #  revert_dir  =  revert     #  verify_dir  =  verify     #  extension  =  sql   #  [core  "pg"]     #  target  =  db:pg:     #  registry  =  sqitch     #  client  =  psql  
  132. sqitch.conf sqitch.conf [core]     engine  =  pg    

    #  plan_file  =  sqitch.plan     #  top_dir  =  .     #  deploy_dir  =  deploy     #  revert_dir  =  revert     #  verify_dir  =  verify     #  extension  =  sql   #  [core  "pg"]     #  target  =  db:pg:     #  registry  =  sqitch     #  client  =  psql   --engine pg
  133. What’s the Plan Man? >

  134. What’s the Plan Man?    emacs  sqitch.plan > >

  135. sqitch.plan sqitch.plan %syntax-­‐version=1.0.0-­‐b1   %project=flipr   %uri=https://github.com/theory/agile-­‐flipr

  136. sqitch.plan sqitch.plan %syntax-­‐version=1.0.0-­‐b1   %project=flipr   %uri=https://github.com/theory/agile-­‐flipr Identified

  137. Make It So >

  138. Make It So >    git  add  . >  git

     commit  -­‐m  'Initialize  Sqitch  configuration.' [master  e56e7c8]  Initialize  Sqitch  configuration.  2  files  changed,  16  insertions(+)  create  mode  100644  sqitch.conf  create  mode  100644  sqitch.plan >
  139. Make It So >    git  add  . >  git

     commit  -­‐m  'Initialize  Sqitch  configuration.' [master  e56e7c8]  Initialize  Sqitch  configuration.  2  files  changed,  16  insertions(+)  create  mode  100644  sqitch.conf  create  mode  100644  sqitch.plan >
  140. Make It So >    git  add  . >  git

     commit  -­‐m  'Initialize  Sqitch  configuration.' [master  e56e7c8]  Initialize  Sqitch  configuration.  2  files  changed,  16  insertions(+)  create  mode  100644  sqitch.conf  create  mode  100644  sqitch.plan >
  141. Make It So >    git  add  . >  git

     commit  -­‐m  'Initialize  Sqitch  configuration.' [master  e56e7c8]  Initialize  Sqitch  configuration.  2  files  changed,  16  insertions(+)  create  mode  100644  sqitch.conf  create  mode  100644  sqitch.plan >    git  push Counting  objects:  5,  done. Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (4/4),  done. Writing  objects:  100%  (4/4),  555  bytes,  done. Total  4  (delta  0),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git      9531fab..e56e7c8    master  -­‐>  master >
  142. Make It So >    git  add  . >  git

     commit  -­‐m  'Initialize  Sqitch  configuration.' [master  e56e7c8]  Initialize  Sqitch  configuration.  2  files  changed,  16  insertions(+)  create  mode  100644  sqitch.conf  create  mode  100644  sqitch.plan >    git  push Counting  objects:  5,  done. Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (4/4),  done. Writing  objects:  100%  (4/4),  555  bytes,  done. Total  4  (delta  0),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git      9531fab..e56e7c8    master  -­‐>  master >
  143. Make It So >    git  add  . >  git

     commit  -­‐m  'Initialize  Sqitch  configuration.' [master  e56e7c8]  Initialize  Sqitch  configuration.  2  files  changed,  16  insertions(+)  create  mode  100644  sqitch.conf  create  mode  100644  sqitch.plan >    git  push Counting  objects:  5,  done. Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (4/4),  done. Writing  objects:  100%  (4/4),  555  bytes,  done. Total  4  (delta  0),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git      9531fab..e56e7c8    master  -­‐>  master >
  144. Where’ve We Been? >

  145.    git  log commit  e56e7c88d85fa84e7f726df36bd0ae7a74a618aa Author:  David  E.  Wheeler  <david@justatheory.com>

    Date:      Tue  Jan  7  15:44:40  2014  -­‐0800        Initialize  Sqitch  configuration. commit  9531fab56ecd9abe77636045584d1dc1b74fbc7b Author:  David  E.  Wheeler  <david@justatheory.com> Date:      Tue  Jan  7  15:18:30  2014  -­‐0800        Initialize  repo,  add  README. Where’ve We Been? >
  146.    git  log commit  e56e7c88d85fa84e7f726df36bd0ae7a74a618aa Author:  David  E.  Wheeler  <david@justatheory.com>

    Date:      Tue  Jan  7  15:44:40  2014  -­‐0800        Initialize  Sqitch  configuration. commit  9531fab56ecd9abe77636045584d1dc1b74fbc7b Author:  David  E.  Wheeler  <david@justatheory.com> Date:      Tue  Jan  7  15:18:30  2014  -­‐0800        Initialize  repo,  add  README. Where’ve We Been? >
  147.    git  log commit  e56e7c88d85fa84e7f726df36bd0ae7a74a618aa Author:  David  E.  Wheeler  <david@justatheory.com>

    Date:      Tue  Jan  7  15:44:40  2014  -­‐0800        Initialize  Sqitch  configuration. commit  9531fab56ecd9abe77636045584d1dc1b74fbc7b Author:  David  E.  Wheeler  <david@justatheory.com> Date:      Tue  Jan  7  15:18:30  2014  -­‐0800        Initialize  repo,  add  README. Where’ve We Been? >
  148. First Change >

  149. First Change >  sqitch  add  appschema  -­‐n  'Adds  flipr  app

     schema.' Created  deploy/appschema.sql Created  revert/appschema.sql Created  verify/appschema.sql Added  "appschema"  to  sqitch.plan > >
  150. First Change >  sqitch  add  appschema  -­‐n  'Adds  flipr  app

     schema.' Created  deploy/appschema.sql Created  revert/appschema.sql Created  verify/appschema.sql Added  "appschema"  to  sqitch.plan > >
  151. First Change >  sqitch  add  appschema  -­‐n  'Adds  flipr  app

     schema.' Created  deploy/appschema.sql Created  revert/appschema.sql Created  verify/appschema.sql Added  "appschema"  to  sqitch.plan > >
  152. First Change >  sqitch  add  appschema  -­‐n  'Adds  flipr  app

     schema.' Created  deploy/appschema.sql Created  revert/appschema.sql Created  verify/appschema.sql Added  "appschema"  to  sqitch.plan > >    emacs  deploy/appschema.sql >
  153. deploy/appschem deploy/appschema.sql -­‐-­‐  Deploy  appschema   ! BEGIN;   !

    ! ! COMMIT; -­‐-­‐  XXX  Add  DDLs  here.
  154. deploy/appschem deploy/appschema.sql -­‐-­‐  Deploy  appschema   ! BEGIN;   !

    ! ! COMMIT; CREATE  SCHEMA  flipr;
  155. >  sqitch  add  appschema  -­‐n  'Adds  flipr  app  schema.'  

    Created  deploy/appschema.sql   Created  revert/appschema.sql   Created  verify/appschema.sql   Added  "appschema"  to  sqitch.plan   > First Change >    emacs  deploy/appschema.sql   >
  156. >  sqitch  add  appschema  -­‐n  'Adds  flipr  app  schema.'  

    Created  deploy/appschema.sql   Created  revert/appschema.sql   Created  verify/appschema.sql   Added  "appschema"  to  sqitch.plan   > First Change >    emacs  deploy/appschema.sql   >    emacs  revert/appschema.sql >
  157. revert/appschem revert/appschema.sql -­‐-­‐  Revert  appschema   ! BEGIN;   !

    ! ! COMMIT; -­‐-­‐  XXX  Add  DDLs  here.
  158. revert/appschem revert/appschema.sql -­‐-­‐  Revert  appschema   ! BEGIN;   !

    ! ! COMMIT; DROP  SCHEMA  flipr;
  159. Make it So! >

  160.    createuser  -­‐s  -­‐U  postgres  `whoami` > Make it So!

    >
  161.    createdb  flipr_test >    createuser  -­‐s  -­‐U  postgres  `whoami`

    > Make it So! >
  162.    createdb  flipr_test >    createuser  -­‐s  -­‐U  postgres  `whoami`

    >    sqitch  deploy  db:pg:flipr_test Adding  registry  tables  to  db:pg:flipr_test Deploying  to  db:pg:flipr_test    +  appschema  ..  ok > Make it So! >
  163.    createdb  flipr_test >    createuser  -­‐s  -­‐U  postgres  `whoami`

    >    sqitch  deploy  db:pg:flipr_test Adding  registry  tables  to  db:pg:flipr_test Deploying  to  db:pg:flipr_test    +  appschema  ..  ok > Make it So! >
  164.    createdb  flipr_test >    createuser  -­‐s  -­‐U  postgres  `whoami`

    >    sqitch  deploy  db:pg:flipr_test Adding  registry  tables  to  db:pg:flipr_test Deploying  to  db:pg:flipr_test    +  appschema  ..  ok > Make it So! >
  165.    createdb  flipr_test >    createuser  -­‐s  -­‐U  postgres  `whoami`

    >    sqitch  deploy  db:pg:flipr_test Adding  registry  tables  to  db:pg:flipr_test Deploying  to  db:pg:flipr_test    +  appschema  ..  ok > Make it So! >
  166.    createdb  flipr_test >    createuser  -­‐s  -­‐U  postgres  `whoami`

    >    sqitch  deploy  db:pg:flipr_test Adding  registry  tables  to  db:pg:flipr_test Deploying  to  db:pg:flipr_test    +  appschema  ..  ok > Make it So!    psql  -­‐d  flipr_test  -­‐c  '\dn  flipr' List  of  schemas  Name    |  Owner   -­‐-­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐-­‐  flipr  |  david > >
  167.    createdb  flipr_test >    createuser  -­‐s  -­‐U  postgres  `whoami`

    >    sqitch  deploy  db:pg:flipr_test Adding  registry  tables  to  db:pg:flipr_test Deploying  to  db:pg:flipr_test    +  appschema  ..  ok > Make it So!    psql  -­‐d  flipr_test  -­‐c  '\dn  flipr' List  of  schemas  Name    |  Owner   -­‐-­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐-­‐  flipr  |  david > Trust, but verify >
  168.    createdb  flipr_test >    createuser  -­‐s  -­‐U  postgres  `whoami`

    >    sqitch  deploy  db:pg:flipr_test Adding  registry  tables  to  db:pg:flipr_test Deploying  to  db:pg:flipr_test    +  appschema  ..  ok > Make it So!    psql  -­‐d  flipr_test  -­‐c  '\dn  flipr' List  of  schemas  Name    |  Owner   -­‐-­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐-­‐  flipr  |  david >    emacs  verify/appschema.sql >
  169. -­‐-­‐  Verify  appschema   ! BEGIN;   ! ! !

    ROLLBACK; verify/appschem verify/appschema.sql -­‐-­‐  XXX  Add  verifications  here.
  170. -­‐-­‐  Verify  appschema   ! BEGIN;   ! ! !

    ROLLBACK; SELECT  pg_catalog.has_schema_privilege('nada',  'usage'); verify/appschem verify/appschema.sql
  171. -­‐-­‐  Verify  appschema   ! BEGIN;   ! ! !

    ROLLBACK; SELECT  pg_catalog.has_schema_privilege('nada',  'usage'); verify/appschem verify/appschema.sql Let’s try it, first
  172.    emacs  verify/appschema.sql   > Trust, But Verify >

  173.    emacs  verify/appschema.sql   >      sqitch  verify  db:pg:flipr_test

    Verifying  db:pg:flipr_test    *  appschema  ..  psql:verify/appschema.sql:5:   ERROR:    schema  "nada"  does  not  exist #  Verify  script  "verify/appschema.sql"  failed. not  ok Verify  Summary  Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ Changes:  1 Errors:    1 Verify  failed > Trust, But Verify >
  174.    emacs  verify/appschema.sql   >      sqitch  verify  db:pg:flipr_test

    Verifying  db:pg:flipr_test    *  appschema  ..  psql:verify/appschema.sql:5:   ERROR:    schema  "nada"  does  not  exist #  Verify  script  "verify/appschema.sql"  failed. not  ok Verify  Summary  Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ Changes:  1 Errors:    1 Verify  failed > Trust, But Verify >
  175.    emacs  verify/appschema.sql   >      sqitch  verify  db:pg:flipr_test

    Verifying  db:pg:flipr_test    *  appschema  ..  psql:verify/appschema.sql:5:   ERROR:    schema  "nada"  does  not  exist #  Verify  script  "verify/appschema.sql"  failed. not  ok Verify  Summary  Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ Changes:  1 Errors:    1 Verify  failed > Trust, But Verify >
  176.    emacs  verify/appschema.sql   >      sqitch  verify  db:pg:flipr_test

    Verifying  db:pg:flipr_test    *  appschema  ..  psql:verify/appschema.sql:5:   ERROR:    schema  "nada"  does  not  exist #  Verify  script  "verify/appschema.sql"  failed. not  ok Verify  Summary  Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ Changes:  1 Errors:    1 Verify  failed > Trust, But Verify >
  177. Trust, But Verify >

  178.    perl  -­‐i  -­‐pe  's/nada/flipr/'  verify/appschema.sql >   Trust, But

    Verify >
  179.    sqitch  verify  db:pg:flipr_test Verifying  db:pg:flipr_test    *  appschema  ..

     ok Verify  successful >    perl  -­‐i  -­‐pe  's/nada/flipr/'  verify/appschema.sql >   Trust, But Verify > Mo betta.
  180. > How’s it Look?

  181. > How’s it Look? >  sqitch  status  db:pg:flipr_test #  On

     database  db:pg:flipr_test #  Project:    flipr #  Change:      e01feba4bb79607339a13981574855b6e2aa7526 #  Name:          appschema #  Deployed:  2014-­‐01-­‐07  16:07:22  -­‐0800 #  By:              David  E.  Wheeler  <david@justatheory.com> #   Nothing  to  deploy  (up-­‐to-­‐date)
  182. > How’s it Look? >  sqitch  status  db:pg:flipr_test #  On

     database  db:pg:flipr_test #  Project:    flipr #  Change:      e01feba4bb79607339a13981574855b6e2aa7526 #  Name:          appschema #  Deployed:  2014-­‐01-­‐07  16:07:22  -­‐0800 #  By:              David  E.  Wheeler  <david@justatheory.com> #   Nothing  to  deploy  (up-­‐to-­‐date)
  183. > How’s it Look? >  sqitch  status  db:pg:flipr_test #  On

     database  db:pg:flipr_test #  Project:    flipr #  Change:      e01feba4bb79607339a13981574855b6e2aa7526 #  Name:          appschema #  Deployed:  2014-­‐01-­‐07  16:07:22  -­‐0800 #  By:              David  E.  Wheeler  <david@justatheory.com> #   Nothing  to  deploy  (up-­‐to-­‐date)
  184. > How’s it Look? >  sqitch  status  db:pg:flipr_test #  On

     database  db:pg:flipr_test #  Project:    flipr #  Change:      e01feba4bb79607339a13981574855b6e2aa7526 #  Name:          appschema #  Deployed:  2014-­‐01-­‐07  16:07:22  -­‐0800 #  By:              David  E.  Wheeler  <david@justatheory.com> #   Nothing  to  deploy  (up-­‐to-­‐date)
  185. > How’s it Look? >  sqitch  status  db:pg:flipr_test #  On

     database  db:pg:flipr_test #  Project:    flipr #  Change:      e01feba4bb79607339a13981574855b6e2aa7526 #  Name:          appschema #  Deployed:  2014-­‐01-­‐07  16:07:22  -­‐0800 #  By:              David  E.  Wheeler  <david@justatheory.com> #   Nothing  to  deploy  (up-­‐to-­‐date)
  186. > How’s it Look? >  sqitch  status  db:pg:flipr_test #  On

     database  db:pg:flipr_test #  Project:    flipr #  Change:      e01feba4bb79607339a13981574855b6e2aa7526 #  Name:          appschema #  Deployed:  2014-­‐01-­‐07  16:07:22  -­‐0800 #  By:              David  E.  Wheeler  <david@justatheory.com> #   Nothing  to  deploy  (up-­‐to-­‐date)
  187. Go Back >

  188. >  sqitch  revert  db:pg:flipr_test            

          Revert  all  changes  from  db:pg:flipr_test?  [Yes]   Go Back > ▮
  189. >  sqitch  revert  db:pg:flipr_test            

          Revert  all  changes  from  db:pg:flipr_test?  [Yes]   Go Back > ▮
  190. >  sqitch  revert  db:pg:flipr_test            

          Revert  all  changes  from  db:pg:flipr_test?  [Yes]   Go Back >    -­‐  appschema  ..  ok >
  191. >  sqitch  revert  db:pg:flipr_test            

          Revert  all  changes  from  db:pg:flipr_test?  [Yes]   Go Back >    psql  -­‐d  flipr_test  -­‐c  '\dn  flipr'                        List  of  roles List  of  schemas  Name  |  Owner   -­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐-­‐ >    -­‐  appschema  ..  ok >
  192. >  sqitch  revert  db:pg:flipr_test            

          Revert  all  changes  from  db:pg:flipr_test?  [Yes]   Go Back >    psql  -­‐d  flipr_test  -­‐c  '\dn  flipr'                        List  of  roles List  of  schemas  Name  |  Owner   -­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐-­‐ >    -­‐  appschema  ..  ok >      sqitch  status  db:pg:flipr_test #  On  database  db:pg:flipr_test No  changes  deployed >
  193. History >

  194. History > >  sqitch  log  db:pg:flipr_test On  database  flipr_test Revert

     e01feba4bb79607339a13981574855b6e2aa7526 Name:            appschema Committer:  David  E.  Wheeler  <david@justatheory.com> Date:            2014-­‐01-­‐07  16:07:44  -­‐0800        Adds  flipr  app  schema. Deploy  e01feba4bb79607339a13981574855b6e2aa7526 Name:            appschema Committer:  David  E.  Wheeler  <david@justatheory.com> Date:            2014-­‐01-­‐07  16:07:22  -­‐0800        Adds  flipr  app  schema.
  195. History > >  sqitch  log  db:pg:flipr_test On  database  flipr_test Revert

     e01feba4bb79607339a13981574855b6e2aa7526 Name:            appschema Committer:  David  E.  Wheeler  <david@justatheory.com> Date:            2014-­‐01-­‐07  16:07:44  -­‐0800        Adds  flipr  app  schema. Deploy  e01feba4bb79607339a13981574855b6e2aa7526 Name:            appschema Committer:  David  E.  Wheeler  <david@justatheory.com> Date:            2014-­‐01-­‐07  16:07:22  -­‐0800        Adds  flipr  app  schema.
  196. History > >  sqitch  log  db:pg:flipr_test On  database  flipr_test Revert

     e01feba4bb79607339a13981574855b6e2aa7526 Name:            appschema Committer:  David  E.  Wheeler  <david@justatheory.com> Date:            2014-­‐01-­‐07  16:07:44  -­‐0800        Adds  flipr  app  schema. Deploy  e01feba4bb79607339a13981574855b6e2aa7526 Name:            appschema Committer:  David  E.  Wheeler  <david@justatheory.com> Date:            2014-­‐01-­‐07  16:07:22  -­‐0800        Adds  flipr  app  schema.
  197. Commit It! >

  198. Commit It! >    git  add  . >  git  commit

     -­‐m  'Add  flipr  schema.' [master  07548c2]  Add  flipr  schema.  4  files  changed,  22  insertions(+)  create  mode  100644  deploy/appschema.sql  create  mode  100644  revert/appschema.sql  create  mode  100644  verify/appschema.sql >
  199. Commit It! >    git  add  . >  git  commit

     -­‐m  'Add  flipr  schema.' [master  07548c2]  Add  flipr  schema.  4  files  changed,  22  insertions(+)  create  mode  100644  deploy/appschema.sql  create  mode  100644  revert/appschema.sql  create  mode  100644  verify/appschema.sql >
  200. Commit It! >    git  add  . >  git  commit

     -­‐m  'Add  flipr  schema.' [master  07548c2]  Add  flipr  schema.  4  files  changed,  22  insertions(+)  create  mode  100644  deploy/appschema.sql  create  mode  100644  revert/appschema.sql  create  mode  100644  verify/appschema.sql >
  201. Commit It! >    git  add  . >  git  commit

     -­‐m  'Add  flipr  schema.' [master  07548c2]  Add  flipr  schema.  4  files  changed,  22  insertions(+)  create  mode  100644  deploy/appschema.sql  create  mode  100644  revert/appschema.sql  create  mode  100644  verify/appschema.sql >    git  push Counting  objects:  11,  done. Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (6/6),  done. Writing  objects:  100%  (9/9),  950  bytes,  done. Total  9  (delta  0),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git      e56e7c8..07548c2    master  -­‐>  master
  202. Commit It! >    git  add  . >  git  commit

     -­‐m  'Add  flipr  schema.' [master  07548c2]  Add  flipr  schema.  4  files  changed,  22  insertions(+)  create  mode  100644  deploy/appschema.sql  create  mode  100644  revert/appschema.sql  create  mode  100644  verify/appschema.sql >    git  push Counting  objects:  11,  done. Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (6/6),  done. Writing  objects:  100%  (9/9),  950  bytes,  done. Total  9  (delta  0),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git      e56e7c8..07548c2    master  -­‐>  master
  203. Redeploy >

  204. >  sqitch  deploy  db:pg:flipr_test  -­‐-­‐verify Deploying  changes  to  flipr_test  

     +  appschema  ..  ok > Redeploy >
  205. >  sqitch  deploy  db:pg:flipr_test  -­‐-­‐verify Deploying  changes  to  flipr_test  

     +  appschema  ..  ok > Redeploy > Integrated!
  206. >  sqitch  deploy  db:pg:flipr_test  -­‐-­‐verify Deploying  changes  to  flipr_test  

     +  appschema  ..  ok > Redeploy >
  207. >  sqitch  deploy  db:pg:flipr_test  -­‐-­‐verify Deploying  changes  to  flipr_test  

     +  appschema  ..  ok > Redeploy >    psql  -­‐d  flipr_test  -­‐c  '\dn  flipr' List  of  schemas  Name    |  Owner   -­‐-­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐-­‐  flipr  |  david >
  208. Status Update >

  209. >  sqitch  status  db:pg:flipr_test #  On  database  db:pg:flipr_test #  Project:

       flipr #  Change:      e01feba4bb79607339a13981574855b6e2aa7526 #  Name:          appschema #  Deployed:  2014-­‐01-­‐07  16:13:50  -­‐0800 #  By:              David  E.  Wheeler  <david@justatheory.com> #   Nothing  to  deploy  (up-­‐to-­‐date) > Status Update >
  210. On Target >

  211. On Target >    sqitch  target  add  flipr_test  db:pg:flipr_test >

    Like Git Remotes
  212. On Target >    sqitch  target  add  flipr_test  db:pg:flipr_test >

       sqitch  config  core.pg.target  flipr_test >
  213. On Target >    sqitch  target  add  flipr_test  db:pg:flipr_test >

       sqitch  config  core.pg.target  flipr_test > >  sqitch  status #  On  database  flipr_test #  Project:    flipr #  Change:      e01feba4bb79607339a13981574855b6e2aa7526 #  Name:          appschema #  Deployed:  2014-­‐01-­‐07  16:13:50  -­‐0800 #  By:              David  E.  Wheeler  <david@justatheory.com> #   Nothing  to  deploy  (up-­‐to-­‐date) > No URI
  214. On Target >    sqitch  target  add  flipr_test  db:pg:flipr_test >

       sqitch  config  core.pg.target  flipr_test > >  sqitch  config  -­‐-­‐bool  deploy.verify  true >  sqitch  config  -­‐-­‐bool  rebase.verify  true > >  sqitch  status #  On  database  flipr_test #  Project:    flipr #  Change:      e01feba4bb79607339a13981574855b6e2aa7526 #  Name:          appschema #  Deployed:  2014-­‐01-­‐07  16:13:50  -­‐0800 #  By:              David  E.  Wheeler  <david@justatheory.com> #   Nothing  to  deploy  (up-­‐to-­‐date) > Always verify.
  215. Commit Config >

  216. Commit Config >    git  add  . >  git  commit

     -­‐m  'Add  target  and  verify  to  config.' [master  099b677]  Add  target  and  verify  to  config.  1  file  changed,  4  insertions(+) >
  217. Commit Config >    git  add  . >  git  commit

     -­‐m  'Add  target  and  verify  to  config.' [master  099b677]  Add  target  and  verify  to  config.  1  file  changed,  4  insertions(+) >
  218. Commit Config >    git  push Counting  objects:  5,  done.

    Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (3/3),  done. Writing  objects:  100%  (3/3),  361  bytes,  done. Total  3  (delta  2),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git      07548c2..099b677    master  -­‐>  master >    git  add  . >  git  commit  -­‐m  'Add  target  and  verify  to  config.' [master  099b677]  Add  target  and  verify  to  config.  1  file  changed,  4  insertions(+) >
  219. Not Migrations? antisocial network

  220. Not Migrations? Incomplete mini-language antisocial network

  221. Not Migrations? Incomplete mini-language No logical replication integration antisocial network

  222. Not Migrations? Incomplete mini-language No logical replication integration Numbered scripts

    difficult to track antisocial network
  223. Not Migrations? Incomplete mini-language No logical replication integration Numbered scripts

    difficult to track No VCS awareness antisocial network
  224. SQL Migrations? Incomplete mini-language No logical replication integration Numbered scripts

    hard to track No VCS awareness antisocial network
  225. SQL Migrations? Incomplete mini-language No logical replication integration Numbered scripts

    hard to track No VCS awareness ——————————————— antisocial network
  226. SQL Migrations? Incomplete mini-language No logical replication integration Numbered scripts

    hard to track No VCS awareness ——————————————— ——————————————————— antisocial network
  227. SQL Migrations? Incomplete mini-language No logical replication integration Numbered scripts

    hard to track No VCS awareness ——————————————— ——————————————————— antisocial network
  228. Sq—what? sql anges ch antisocial network

  229. Sq—what? sq ch antisocial network

  230. it Sq—what? sq ch antisocial network

  231. it Sq—what? sq ch There is no “u” antisocial network

  232. Sqitch Philosophy antisocial network

  233. Sqitch Philosophy No opinions antisocial network

  234. Sqitch Philosophy No opinions Native scripting (psql, sqlite3, SQL*Plus) antisocial

    network
  235. Sqitch Philosophy No opinions Native scripting (psql, sqlite3, SQL*Plus) Cross-project

    dependency resolution antisocial network
  236. Sqitch Philosophy No opinions Native scripting (psql, sqlite3, SQL*Plus) Cross-project

    dependency resolution Distribution bundling antisocial network
  237. Sqitch Philosophy No opinions Native scripting (psql, sqlite3, SQL*Plus) Cross-project

    dependency resolution Distribution bundling Integrated verification testing antisocial network
  238. Sqitch Philosophy No opinions Native scripting (psql, sqlite3, SQL*Plus) Cross-project

    dependency resolution Distribution bundling Integrated verification testing No numbering antisocial network
  239. Sqitch Philosophy No opinions Native scripting (psql, sqlite3, SQL*Plus) Cross-project

    dependency resolution Distribution bundling Integrated verification testing No numbering Reliable sequential deployment ordering antisocial network
  240. SHAzbat antisocial network

  241. SHAzbat SHA1 ID for every object antisocial network

  242. SHAzbat SHA1 ID for every object Stolen from Git antisocial

    network
  243. SHAzbat SHA1 ID for every object Stolen from Git change,

    tag, deploy, revert, verify antisocial network
  244. SHAzbat SHA1 ID for every object Stolen from Git change,

    tag, deploy, revert, verify Hashed change text includes: antisocial network
  245. SHAzbat SHA1 ID for every object Stolen from Git change,

    tag, deploy, revert, verify Hashed change text includes: Project antisocial network
  246. SHAzbat SHA1 ID for every object Stolen from Git change,

    tag, deploy, revert, verify Hashed change text includes: Project Name antisocial network
  247. SHAzbat SHA1 ID for every object Stolen from Git change,

    tag, deploy, revert, verify Hashed change text includes: Project Name Parent ID antisocial network
  248. SHAzbat SHA1 ID for every object Stolen from Git change,

    tag, deploy, revert, verify Hashed change text includes: Project Name Parent ID Planner… antisocial network
  249. SHAsome >

  250. SHAsome >    sqitch  show  change  @HEAD project  pgxn_manager uri

     https://github.com/pgxn/pgxn-­‐manager.git change  distview parent  39d7e105cb00e1798cfabb45f4b74cbc14a82513 planner  David  E.  Wheeler  <david@justatheory.com> date  2013-­‐02-­‐08T23:51:19Z requires    +  roles    +  pgxn_core:types    +  distributions    +  extensions Adds  the  filters  table. >
  251. SHAsome >    sqitch  show  change  @HEAD project  pgxn_manager uri

     https://github.com/pgxn/pgxn-­‐manager.git change  distview parent  39d7e105cb00e1798cfabb45f4b74cbc14a82513 planner  David  E.  Wheeler  <david@justatheory.com> date  2013-­‐02-­‐08T23:51:19Z requires    +  roles    +  pgxn_core:types    +  distributions    +  extensions Adds  the  filters  table. > Symbolic Sqitch tag
  252. SHAsome >    sqitch  show  change  @HEAD project  pgxn_manager uri

     https://github.com/pgxn/pgxn-­‐manager.git change  distview parent  39d7e105cb00e1798cfabb45f4b74cbc14a82513 planner  David  E.  Wheeler  <david@justatheory.com> date  2013-­‐02-­‐08T23:51:19Z requires    +  roles    +  pgxn_core:types    +  distributions    +  extensions Adds  the  filters  table. >
  253. SHAsome >    sqitch  show  change  @HEAD project  pgxn_manager uri

     https://github.com/pgxn/pgxn-­‐manager.git change  distview parent  39d7e105cb00e1798cfabb45f4b74cbc14a82513 planner  David  E.  Wheeler  <david@justatheory.com> date  2013-­‐02-­‐08T23:51:19Z requires    +  roles    +  pgxn_core:types    +  distributions    +  extensions Adds  the  filters  table. >
  254. SHAsome >    sqitch  show  change  @HEAD project  pgxn_manager uri

     https://github.com/pgxn/pgxn-­‐manager.git change  distview parent  39d7e105cb00e1798cfabb45f4b74cbc14a82513 planner  David  E.  Wheeler  <david@justatheory.com> date  2013-­‐02-­‐08T23:51:19Z requires    +  roles    +  pgxn_core:types    +  distributions    +  extensions Adds  the  filters  table. >
  255. SHAsome >    sqitch  show  change  @HEAD project  pgxn_manager uri

     https://github.com/pgxn/pgxn-­‐manager.git change  distview parent  39d7e105cb00e1798cfabb45f4b74cbc14a82513 planner  David  E.  Wheeler  <david@justatheory.com> date  2013-­‐02-­‐08T23:51:19Z requires    +  roles    +  pgxn_core:types    +  distributions    +  extensions Adds  the  filters  table. >
  256. SHAsome >    sqitch  show  change  @HEAD project  pgxn_manager uri

     https://github.com/pgxn/pgxn-­‐manager.git change  distview parent  39d7e105cb00e1798cfabb45f4b74cbc14a82513 planner  David  E.  Wheeler  <david@justatheory.com> date  2013-­‐02-­‐08T23:51:19Z requires    +  roles    +  pgxn_core:types    +  distributions    +  extensions Adds  the  filters  table. >
  257. SHAsome >    sqitch  show  change  @HEAD project  pgxn_manager uri

     https://github.com/pgxn/pgxn-­‐manager.git change  distview parent  39d7e105cb00e1798cfabb45f4b74cbc14a82513 planner  David  E.  Wheeler  <david@justatheory.com> date  2013-­‐02-­‐08T23:51:19Z requires    +  roles    +  pgxn_core:types    +  distributions    +  extensions Adds  the  filters  table. >
  258. SHAsome >    sqitch  show  change  @HEAD project  pgxn_manager uri

     https://github.com/pgxn/pgxn-­‐manager.git change  distview parent  39d7e105cb00e1798cfabb45f4b74cbc14a82513 planner  David  E.  Wheeler  <david@justatheory.com> date  2013-­‐02-­‐08T23:51:19Z requires    +  roles    +  pgxn_core:types    +  distributions    +  extensions Adds  the  filters  table. >
  259. SHAsome >    sqitch  show  change  @HEAD project  pgxn_manager uri

     https://github.com/pgxn/pgxn-­‐manager.git change  distview parent  39d7e105cb00e1798cfabb45f4b74cbc14a82513 planner  David  E.  Wheeler  <david@justatheory.com> date  2013-­‐02-­‐08T23:51:19Z requires    +  roles    +  pgxn_core:types    +  distributions    +  extensions Adds  the  filters  table. >
  260. SHAsome >    sqitch  show  change  @HEAD project  pgxn_manager uri

     https://github.com/pgxn/pgxn-­‐manager.git change  distview parent  39d7e105cb00e1798cfabb45f4b74cbc14a82513 planner  David  E.  Wheeler  <david@justatheory.com> date  2013-­‐02-­‐08T23:51:19Z requires    +  roles    +  pgxn_core:types    +  distributions    +  extensions Adds  the  filters  table. >
  261. SHApay! antisocial network

  262. SHApay! Each change (except first) includes parent antisocial network

  263. SHApay! Each change (except first) includes parent Can trace from

    any change to the beginning antisocial network
  264. SHApay! Each change (except first) includes parent Can trace from

    any change to the beginning Change tampering (corruption) detectable antisocial network
  265. SHApay! Each change (except first) includes parent Can trace from

    any change to the beginning Change tampering (corruption) detectable Because the hash will be wrong antisocial network
  266. SHApay! Each change (except first) includes parent Can trace from

    any change to the beginning Change tampering (corruption) detectable Because the hash will be wrong Stole Linus Torvalds’s “greatest invention” antisocial network
  267. Sqitch Features antisocial network

  268. Sqitch Features Reduced duplication antisocial network

  269. Sqitch Features Reduced duplication Built-in configuration antisocial network

  270. Sqitch Features Reduced duplication Built-in configuration Iterative development antisocial network

  271. Sqitch Features Reduced duplication Built-in configuration Iterative development Targeted deployment

    antisocial network
  272. Sqitch Features Reduced duplication Built-in configuration Iterative development Targeted deployment

    Git-style interface antisocial network
  273. Sqitch Features Reduced duplication Built-in configuration Iterative development Targeted deployment

    Git-style interface Deployment tagging antisocial network
  274. antisocial network Your Turn

  275. antisocial network Your Turn Configure Sqitch

  276. antisocial network Your Turn Configure Sqitch Initialize project

  277. antisocial network Your Turn Configure Sqitch Initialize project Add appschema

    change
  278. antisocial network Your Turn Configure Sqitch Initialize project Add appschema

    change Deploy/Revert
  279. antisocial network Your Turn Configure Sqitch Initialize project Add appschema

    change Deploy/Revert Commit/push
  280. antisocial network Your Turn Configure Sqitch Initialize project Add appschema

    change Deploy/Revert Commit/push https:/ /github.com/ theory/agile-flipr.git
  281. Add Tests >

  282. Add Tests >    mkdir  test >

  283. Add Tests >    mkdir  test >    emacs  test/appschema.sql

    >
  284. test/appschema. pgTAP Basics

  285. test/appschema. pgTAP Basics SET  client_min_messages  TO  warning; CREATE  EXTENSION  IF

     NOT  EXISTS  pgtap; RESET  client_min_messages; BEGIN; SELECT  plan(1); SELECT  has_schema('nada'); SELECT  finish(); ROLLBACK;
  286. test/appschema. pgTAP Basics SET  client_min_messages  TO  warning; CREATE  EXTENSION  IF

     NOT  EXISTS  pgtap; RESET  client_min_messages; BEGIN; SELECT  plan(1); SELECT  has_schema('nada'); SELECT  finish(); ROLLBACK;
  287. test/appschema. pgTAP Basics SET  client_min_messages  TO  warning; CREATE  EXTENSION  IF

     NOT  EXISTS  pgtap; RESET  client_min_messages; BEGIN; SELECT  plan(1); SELECT  has_schema('nada'); SELECT  finish(); ROLLBACK;
  288. test/appschema. pgTAP Basics SET  client_min_messages  TO  warning; CREATE  EXTENSION  IF

     NOT  EXISTS  pgtap; RESET  client_min_messages; BEGIN; SELECT  plan(1); SELECT  has_schema('nada'); SELECT  finish(); ROLLBACK;
  289. test/appschema. pgTAP Basics SET  client_min_messages  TO  warning; CREATE  EXTENSION  IF

     NOT  EXISTS  pgtap; RESET  client_min_messages; BEGIN; SELECT  plan(1); SELECT  has_schema('nada'); SELECT  finish(); ROLLBACK;
  290. test/appschema. pgTAP Basics SET  client_min_messages  TO  warning; CREATE  EXTENSION  IF

     NOT  EXISTS  pgtap; RESET  client_min_messages; BEGIN; SELECT  plan(1); SELECT  has_schema('nada'); SELECT  finish(); ROLLBACK;
  291. test/appschema. pgTAP Basics SET  client_min_messages  TO  warning; CREATE  EXTENSION  IF

     NOT  EXISTS  pgtap; RESET  client_min_messages; BEGIN; SELECT  plan(1); SELECT  has_schema('nada'); SELECT  finish(); ROLLBACK;
  292. > Run the Test

  293. > Run the Test pg_prove -­‐v -­‐d flipr_test test/appschema.sql test/appschema.sql

    .. 1..1 not ok 1 -­‐ Schema nada should exist # Failed test 1: "Schema nada should exist" # Looks like you failed 1 test of 1 Failed 1/1 subtests Test Summary Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ test/appschema.sql (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs Result: FAIL
  294. > Run the Test pg_prove -­‐v -­‐d flipr_test test/appschema.sql test/appschema.sql

    .. 1..1 not ok 1 -­‐ Schema nada should exist # Failed test 1: "Schema nada should exist" # Looks like you failed 1 test of 1 Failed 1/1 subtests Test Summary Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ test/appschema.sql (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs Result: FAIL
  295. > Run the Test pg_prove -­‐v -­‐d flipr_test test/appschema.sql test/appschema.sql

    .. 1..1 not ok 1 -­‐ Schema nada should exist # Failed test 1: "Schema nada should exist" # Looks like you failed 1 test of 1 Failed 1/1 subtests Test Summary Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ test/appschema.sql (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs Result: FAIL
  296. First Pass >

  297. perl -­‐i -­‐pe 's/nada/flipr/' test/appschema.sql > First Pass >

  298. perl -­‐i -­‐pe 's/nada/flipr/' test/appschema.sql > First Pass > >

    pg_prove -­‐v -­‐d flipr_test test/appschema.sql test/appschema.sql .. 1..1 ok 1 -­‐ Schema flipr should exist ok All tests successful. Files=1, Tests=1, 0 wallclock secs Result: PASS
  299. perl -­‐i -­‐pe 's/nada/flipr/' test/appschema.sql > First Pass W00t! >

    > pg_prove -­‐v -­‐d flipr_test test/appschema.sql test/appschema.sql .. 1..1 ok 1 -­‐ Schema flipr should exist ok All tests successful. Files=1, Tests=1, 0 wallclock secs Result: PASS
  300. Pass it On >

  301. git add . > Pass it On >

  302. git add . > git commit -­‐m 'Add appschema test.'

    [master 92bd85c] Add appschema test. 1 file changed, 14 insertions(+) create mode 100644 test/appschema.sql > Pass it On >
  303. git add . > git commit -­‐m 'Add appschema test.'

    [master 92bd85c] Add appschema test. 1 file changed, 14 insertions(+) create mode 100644 test/appschema.sql > Pass it On > git push Counting objects: 5, done. Delta compression using up to 4 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (4/4), 486 bytes, done. Total 4 (delta 1), reused 0 (delta 0) To ssh://git@source.iovationnp.com:7999/~david.w 099b677..c965fb6 master -­‐> master >
  304. None
  305. OMG TAP WTF?

  306. What is TAP? antisocial network

  307. What does that mean in practice? What is TAP? antisocial

    network
  308. What does that mean in practice? Test output easy to

    interpret What is TAP? antisocial network
  309. What does that mean in practice? Test output easy to

    interpret By humans What is TAP? antisocial network
  310. What does that mean in practice? Test output easy to

    interpret By humans By computers What is TAP? antisocial network
  311. What does that mean in practice? Test output easy to

    interpret By humans By computers pg_prove (the harness) What is TAP? antisocial network
  312. What does that mean in practice? Test output easy to

    interpret By humans By computers pg_prove (the harness) By aliens What is TAP? antisocial network
  313. What does that mean in practice? Test output easy to

    interpret By humans By computers pg_prove (the harness) By aliens By gum! What is TAP? antisocial network
  314. What’s the plan, man? antisocial network

  315. What’s the plan, man? Includes Test controls: antisocial network

  316. What’s the plan, man? Includes Test controls: plan() — How

    many tests? antisocial network
  317. What’s the plan, man? Includes Test controls: plan() — How

    many tests? no_plan() — Unknown number of tests antisocial network
  318. What’s the plan, man? Includes Test controls: plan() — How

    many tests? no_plan() — Unknown number of tests diag() — Diagnostic output antisocial network
  319. What’s the plan, man? Includes Test controls: plan() — How

    many tests? no_plan() — Unknown number of tests diag() — Diagnostic output finish() — Test finished, report! antisocial network
  320. Scalarly antisocial network

  321. Scalarly Includes simple scalar test functions: antisocial network

  322. Scalarly Includes simple scalar test functions: ok() — Boolean antisocial

    network
  323. Scalarly Includes simple scalar test functions: ok() — Boolean is()

    — Value comparison antisocial network
  324. Scalarly Includes simple scalar test functions: ok() — Boolean is()

    — Value comparison isnt() — NOT is() antisocial network
  325. Scalarly Includes simple scalar test functions: ok() — Boolean is()

    — Value comparison isnt() — NOT is() cmp_ok() — Compare with specific operator antisocial network
  326. Scalarly Includes simple scalar test functions: ok() — Boolean is()

    — Value comparison isnt() — NOT is() cmp_ok() — Compare with specific operator matches() — Regex comparison antisocial network
  327. Scalarly Includes simple scalar test functions: ok() — Boolean is()

    — Value comparison isnt() — NOT is() cmp_ok() — Compare with specific operator matches() — Regex comparison imatches() — Case-insensitive regex comparison antisocial network
  328. It’s All Relative antisocial network

  329. It’s All Relative Includes functions for testing relations: antisocial network

  330. It’s All Relative Includes functions for testing relations: results_eq() —

    Ordered results antisocial network
  331. It’s All Relative Includes functions for testing relations: results_eq() —

    Ordered results set_eq() — Set of values antisocial network
  332. It’s All Relative Includes functions for testing relations: results_eq() —

    Ordered results set_eq() — Set of values bag_eq() — Bag of values antisocial network
  333. It’s All Relative Includes functions for testing relations: results_eq() —

    Ordered results set_eq() — Set of values bag_eq() — Bag of values row_eq() — Single row antisocial network
  334. It’s All Relative Includes functions for testing relations: results_eq() —

    Ordered results set_eq() — Set of values bag_eq() — Bag of values row_eq() — Single row is_empty() — No results antisocial network
  335. I’m Okay, You’re Okay antisocial network

  336. I’m Okay, You’re Okay throws_ok() — Throws an exception antisocial

    network
  337. I’m Okay, You’re Okay throws_ok() — Throws an exception throws_like()

    — Exception matches regex antisocial network
  338. I’m Okay, You’re Okay throws_ok() — Throws an exception throws_like()

    — Exception matches regex skip() — Skip a subset of tests antisocial network
  339. I’m Okay, You’re Okay throws_ok() — Throws an exception throws_like()

    — Exception matches regex skip() — Skip a subset of tests todo() — Expect subset of tests to fail antisocial network
  340. Schematics antisocial network

  341. Schematics has_table(), has_view(), has_function(), etc. antisocial network

  342. Schematics has_table(), has_view(), has_function(), etc. columns_are(), has_pk(), fk_ok(), etc. antisocial

    network
  343. Schematics has_table(), has_view(), has_function(), etc. columns_are(), has_pk(), fk_ok(), etc. col_type_is(),

    col_not_null(), col_default_is() antisocial network
  344. Schematics has_table(), has_view(), has_function(), etc. columns_are(), has_pk(), fk_ok(), etc. col_type_is(),

    col_not_null(), col_default_is() So, so much more… antisocial network
  345. Other Features and Topics antisocial network

  346. Other Features and Topics xUnit-Style testing antisocial network

  347. Other Features and Topics xUnit-Style testing Test-Driven development antisocial network

  348. Other Features and Topics xUnit-Style testing Test-Driven development Integration with

    Perl unit tests antisocial network
  349. Other Features and Topics xUnit-Style testing Test-Driven development Integration with

    Perl unit tests Integration with pg_regress antisocial network
  350. Other Features and Topics xUnit-Style testing Test-Driven development Integration with

    Perl unit tests Integration with pg_regress Negative assertions antisocial network
  351. Other Features and Topics xUnit-Style testing Test-Driven development Integration with

    Perl unit tests Integration with pg_regress Negative assertions Role and privilege assertions antisocial network
  352. Other Features and Topics xUnit-Style testing Test-Driven development Integration with

    Perl unit tests Integration with pg_regress Negative assertions Role and privilege assertions http:/ /pgtap.org/ antisocial network
  353. Other Features and Topics xUnit-Style testing Test-Driven development Integration with

    Perl unit tests Integration with pg_regress Negative assertions Role and privilege assertions http:/ /pgtap.org/ http:/ /pgxn.org/extension/pgtap/ antisocial network
  354. antisocial network Let’s do it!

  355. antisocial network Let’s do it! Create appschema test

  356. antisocial network Let’s do it! Create appschema test Use pgTAP

  357. antisocial network Let’s do it! Create appschema test Use pgTAP

    Run test with pg_prove
  358. antisocial network Let’s do it! Create appschema test Use pgTAP

    Run test with pg_prove Make it fail
  359. antisocial network Let’s do it! Create appschema test Use pgTAP

    Run test with pg_prove Make it fail Make it pass!
  360. antisocial network Let’s do it! Create appschema test Use pgTAP

    Run test with pg_prove Make it fail Make it pass! Commit/Push
  361. antisocial network Let’s do it! Create appschema test Use pgTAP

    Run test with pg_prove Make it fail Make it pass! Commit/Push https:/ /github.com/ theory/agile-flipr.git
  362. Let’s talk about… antisocial network antisocial network antisocial network

  363. antisocial network antisocial network

  364. TDD antisocial network antisocial network

  365. antisocial network

  366. TDD is an act of design. antisocial network

  367. antisocial network

  368. TDD is an act of documentation. antisocial network

  369. Database Design antisocial network

  370. Database Design Specify requirements antisocial network

  371. Database Design Specify requirements Implement schema design antisocial network

  372. Database Design Specify requirements Implement schema design Program applications antisocial

    network
  373. Database Design Specify requirements Implement schema design Program applications QA

    antisocial network
  374. Database Design Specify requirements Implement schema design Program applications QA

    Big jump! antisocial network
  375. Database Design Specify requirements Implement schema design Program applications QA

    Pricy to fix antisocial network
  376. Database Design Specify requirements Implement schema design Program applications QA

    Never mind busy DBA schedules! antisocial network
  377. Why TDDD antisocial network

  378. Why TDDD Ensure data quality antisocial network

  379. Why TDDD Ensure data quality Data is a core asset

    antisocial network
  380. Why TDDD Ensure data quality Data is a core asset

    Validate business rules antisocial network
  381. Why TDDD Ensure data quality Data is a core asset

    Validate business rules Stored procedures antisocial network
  382. Why TDDD Ensure data quality Data is a core asset

    Validate business rules Stored procedures Triggers antisocial network
  383. Why TDDD Ensure data quality Data is a core asset

    Validate business rules Stored procedures Triggers Views antisocial network
  384. Why TDDD antisocial network

  385. Why TDDD Identify defects early antisocial network

  386. Why TDDD Identify defects early …and often! antisocial network

  387. Why TDDD Identify defects early …and often! Create design iteratively

    antisocial network
  388. Why TDDD Identify defects early …and often! Create design iteratively

    Evolutionarily antisocial network
  389. Why TDDD Identify defects early …and often! Create design iteratively

    Evolutionarily Validate refactorings antisocial network
  390. Why TDDD Identify defects early …and often! Create design iteratively

    Evolutionarily Validate refactorings Make sure nothing breaks antisocial network
  391. Three Questions for Database Professionals from Scott Ambler antisocial network

  392. None
  393. “If you’re implementing code in the DB in the form

    of stored procedures, triggers... shouldn’t you test that code to the same level that you test your app code?”
  394. None
  395. “Think of all the data quality problems you’ve run into

    over the years. Wouldn't it have been nice if someone had originally tested and discovered those problems before you did?”
  396. None
  397. “Wouldn’t it be nice to have a test suite to

    run so that you could determine how (and if) the DB actually works?”
  398. antisocial network

  399. Okay. antisocial network

  400. antisocial network

  401. How? antisocial network

  402. TDD How antisocial network

  403. TDD How Ideally separate from app tests antisocial network

  404. TDD How Ideally separate from app tests May be many

    apps antisocial network
  405. TDD How Ideally separate from app tests May be many

    apps DB should present interface to all antisocial network
  406. TDD How Ideally separate from app tests May be many

    apps DB should present interface to all Apps may use different permissions antisocial network
  407. TDD How Ideally separate from app tests May be many

    apps DB should present interface to all Apps may use different permissions Ideally use DB test Framework antisocial network
  408. TDD How Ideally separate from app tests May be many

    apps DB should present interface to all Apps may use different permissions Ideally use DB test Framework Like…pgTAP! antisocial network
  409. Test Template

  410. Test Template Sqitch scripts generated from templates

  411. Test Template Sqitch scripts generated from templates Can add new

    templates for new files
  412. Test Template Sqitch scripts generated from templates Can add new

    templates for new files Always want test for change?
  413. Test Template Sqitch scripts generated from templates Can add new

    templates for new files Always want test for change? Add test template!
  414. Templates Where? >

  415. Templates Where?    mkdir  -­‐p  ~/.sqitch/templates/test > > Or system-wide:


    `sqitch --etc-path`/templates
  416. Templates Where?    mkdir  -­‐p  ~/.sqitch/templates/test > >    cp

     test/appschema.sql  ~/.sqitch/templates/test/pg.tmpl > Will create file in project test directory.
  417.    emacs  ~/.sqitch/templates/test/pg.tmpl > Templates Where?    mkdir  -­‐p  ~/.sqitch/templates/test

    > >    cp  test/appschema.sql  ~/.sqitch/templates/test/pg.tmpl >
  418. pg.tmpl Template Your Tests SET  client_min_messages  TO  warning;   CREATE

     EXTENSION  IF  NOT  EXISTS  pgtap;   RESET  client_min_messages;   ! BEGIN;   ! ! ! SELECT   ! SELECT  finish();   ROLLBACK; has_schema('flipr'); SELECT  plan(1);  
  419. pg.tmpl Template Your Tests SET  client_min_messages  TO  warning;   CREATE

     EXTENSION  IF  NOT  EXISTS  pgtap;   RESET  client_min_messages;   ! BEGIN;   ! ! ! SELECT   ! SELECT  finish();   ROLLBACK; has_schema('flipr'); Adjust test counts. SELECT  no_plan(); -­‐-­‐  SELECT  plan(1);
  420. pg.tmpl Template Your Tests SET  client_min_messages  TO  warning;   CREATE

     EXTENSION  IF  NOT  EXISTS  pgtap;   RESET  client_min_messages;   ! BEGIN;   ! ! ! SELECT   ! SELECT  finish();   ROLLBACK; pass('Test  [%  change  %]!'); Put tests here. SELECT  no_plan(); -­‐-­‐  SELECT  plan(1);
  421. Branching Out >

  422.    git  checkout  -­‐b  users  master Switched  to  a  new

     branch  'users' > Branching Out >
  423.    git  checkout  -­‐b  users  master Switched  to  a  new

     branch  'users' > Branching Out > Branched off from others
  424.    git  checkout  -­‐b  users  master Switched  to  a  new

     branch  'users' > Branching Out > >  sqitch  add  users  -­‐-­‐requires  appschema  \    -­‐n  'Creates  table  to  track  our  users.' Created  deploy/users.sql Created  revert/users.sql Created  test/users.sql Created  verify/users.sql Added  "users  [appschema]"  to  sqitch.plan >
  425.    git  checkout  -­‐b  users  master Switched  to  a  new

     branch  'users' > Branching Out > >  sqitch  add  users  -­‐-­‐requires  appschema  \    -­‐n  'Creates  table  to  track  our  users.' Created  deploy/users.sql Created  revert/users.sql Created  test/users.sql Created  verify/users.sql Added  "users  [appschema]"  to  sqitch.plan > Cool!
  426.    git  checkout  -­‐b  users  master Switched  to  a  new

     branch  'users' > Branching Out > >  sqitch  add  users  -­‐-­‐requires  appschema  \    -­‐n  'Creates  table  to  track  our  users.' Created  deploy/users.sql Created  revert/users.sql Created  test/users.sql Created  verify/users.sql Added  "users  [appschema]"  to  sqitch.plan >
  427.    git  checkout  -­‐b  users  master Switched  to  a  new

     branch  'users' > Branching Out > >  emacs  test/users.sql > >  sqitch  add  users  -­‐-­‐requires  appschema  \    -­‐n  'Creates  table  to  track  our  users.' Created  deploy/users.sql Created  revert/users.sql Created  test/users.sql Created  verify/users.sql Added  "users  [appschema]"  to  sqitch.plan >
  428. SET  client_min_messages  TO  warning;   CREATE  EXTENSION  IF  NOT  EXISTS

     pgtap;   RESET  client_min_messages;   ! BEGIN;   SELECT  no_plan();   -­‐-­‐  SELECT  plan(1);   ! ! ! ! test/users.sql Table For One SELECT  pass('Test  users!'); SELECT  finish();   ROLLBACK;
  429. SET  client_min_messages  TO  warning;   CREATE  EXTENSION  IF  NOT  EXISTS

     pgtap;   RESET  client_min_messages;   ! BEGIN;   SELECT  no_plan();   -­‐-­‐  SELECT  plan(1);   ! ! ! ! test/users.sql Table For One SELECT  pass('Test  users!'); SELECT  finish();   ROLLBACK;
  430. SET  client_min_messages  TO  warning;   CREATE  EXTENSION  IF  NOT  EXISTS

     pgtap;   RESET  client_min_messages;   ! BEGIN;   SELECT  no_plan();   -­‐-­‐  SELECT  plan(1);   ! ! ! ! test/users.sql Table For One SET  search_path  TO  flipr,public; SELECT  has_table(  'users'  ); SELECT  finish();   ROLLBACK;
  431. SET  client_min_messages  TO  warning;   CREATE  EXTENSION  IF  NOT  EXISTS

     pgtap;   RESET  client_min_messages;   ! BEGIN;   SELECT  no_plan();   -­‐-­‐  SELECT  plan(1);   ! ! ! ! test/users.sql Table For One SET  search_path  TO  flipr,public; SELECT  has_table(  'users'  ); SELECT  finish();   ROLLBACK;
  432. SET  client_min_messages  TO  warning;   CREATE  EXTENSION  IF  NOT  EXISTS

     pgtap;   RESET  client_min_messages;   ! BEGIN;   SELECT  no_plan();   -­‐-­‐  SELECT  plan(1);   ! ! ! ! test/users.sql Table For One SET  search_path  TO  flipr,public; SELECT  has_table(  'users'  ); SELECT  finish();   ROLLBACK;
  433. Run ’Em >

  434. pg_prove -­‐d flipr_test -­‐v test/users.sql test/users.sql .. not ok 1

    -­‐ Table users should exist # Failed test 1: "Table users should exist" 1..1 # Looks like you failed 1 test of 1 Failed 1/1 subtests Test Summary Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ test/users.sql (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs Result: FAIL > Run ’Em >
  435. pg_prove -­‐d flipr_test -­‐v test/users.sql test/users.sql .. not ok 1

    -­‐ Table users should exist # Failed test 1: "Table users should exist" 1..1 # Looks like you failed 1 test of 1 Failed 1/1 subtests Test Summary Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ test/users.sql (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs Result: FAIL > Run ’Em >
  436. pg_prove -­‐d flipr_test -­‐v test/users.sql test/users.sql .. not ok 1

    -­‐ Table users should exist # Failed test 1: "Table users should exist" 1..1 # Looks like you failed 1 test of 1 Failed 1/1 subtests Test Summary Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ test/users.sql (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs Result: FAIL > Run ’Em As expected. >
  437. pg_prove -­‐d flipr_test -­‐v test/users.sql test/users.sql .. not ok 1

    -­‐ Table users should exist # Failed test 1: "Table users should exist" 1..1 # Looks like you failed 1 test of 1 Failed 1/1 subtests Test Summary Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ test/users.sql (Wstat: 0 Tests: 1 Failed: 1) Failed test: 1 Files=1, Tests=1, 0 wallclock secs Result: FAIL > Run ’Em >    emacs  deploy/users.sql
  438. deploy/users.sq deploy/users.sql -­‐-­‐  XXX  Add  DDLs  here. COMMIT; -­‐-­‐  Deploy

     users   -­‐-­‐  requires:  appschema   ! BEGIN;   ! 

  439. deploy/users.sq deploy/users.sql -­‐-­‐  XXX  Add  DDLs  here. COMMIT; -­‐-­‐  Deploy

     users   -­‐-­‐  requires:  appschema   ! BEGIN;   ! 

  440. SET  client_min_messages  =  'warning'; CREATE  TABLE  flipr.users  (    

       nickname    TEXT ); deploy/users.sq deploy/users.sql COMMIT; -­‐-­‐  Deploy  users   -­‐-­‐  requires:  appschema   ! BEGIN;   ! 

  441. SET  client_min_messages  =  'warning'; CREATE  TABLE  flipr.users  (    

       nickname    TEXT ); deploy/users.sq deploy/users.sql COMMIT; -­‐-­‐  Deploy  users   -­‐-­‐  requires:  appschema   ! BEGIN;   ! 
 Bare Minimum
  442. Verily, Users >    emacs  deploy/users.sql   >

  443. Verily, Users >    emacs  deploy/users.sql   >    emacs

     verify/users.sql
  444. -­‐-­‐  Verify  users   ! BEGIN; verify/users.sq verify/users.sql -­‐-­‐  XXX

     Add  verifications  here. ROLLBACK;
  445. -­‐-­‐  Verify  users   ! BEGIN; SELECT  nickname    FROM

     flipr.users  WHERE  FALSE; verify/users.sq verify/users.sql ROLLBACK;
  446. Unusered > >  emacs  deploy/users.sql   >  emacs  verify/users.sql  

    >
  447. Unusered > >  emacs  deploy/users.sql   >  emacs  verify/users.sql  

    >    emacs  revert/users.sql
  448. revert/users.sq revert/users.sql -­‐-­‐  Revert  users   ! BEGIN;   !

    ! ! COMMIT; -­‐-­‐  XXX  Add  DDLs  here.
  449. revert/users.sq revert/users.sql -­‐-­‐  Revert  users   ! BEGIN;   !

    ! ! COMMIT; DROP  TABLE  flipr.users;
  450. Make Users >

  451.    sqitch  deploy Deploying  changes  to  flipr_test    +  users

     ..  ok > Make Users >
  452.    sqitch  deploy Deploying  changes  to  flipr_test    +  users

     ..  ok > Make Users >
  453.    sqitch  deploy Deploying  changes  to  flipr_test    +  users

     ..  ok > Make Users >    psql  -­‐d  flipr_test  -­‐c  '\d  flipr.users'          Table  "flipr.users"    Column    |  Type  |  Modifiers   -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐  nickname  |  text  |   >
  454.    sqitch  deploy Deploying  changes  to  flipr_test    +  users

     ..  ok > Make Users >    psql  -­‐d  flipr_test  -­‐c  '\d  flipr.users'          Table  "flipr.users"    Column    |  Type  |  Modifiers   -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐  nickname  |  text  |   >    sqitch  verify Verifying  flipr_test    *  appschema  ..  ok    *  users  ......  ok Verify  successful >
  455. Make Users >

  456.    pg_prove  -­‐d  flipr_test  -­‐v  test/users.sql test/users.sql  ..   ok

     1  -­‐  Table  users  should  exist 1..1 ok All  tests  successful. Files=1,  Tests=1,    1  wallclock  secs Result:  PASS > Make Users >
  457.    pg_prove  -­‐d  flipr_test  -­‐v  test/users.sql test/users.sql  ..   ok

     1  -­‐  Table  users  should  exist 1..1 ok All  tests  successful. Files=1,  Tests=1,    1  wallclock  secs Result:  PASS > Make Users >
  458.    pg_prove  -­‐d  flipr_test  -­‐v  test/users.sql test/users.sql  ..   ok

     1  -­‐  Table  users  should  exist 1..1 ok All  tests  successful. Files=1,  Tests=1,    1  wallclock  secs Result:  PASS > Make Users > Woohoo!
  459.    pg_prove  -­‐d  flipr_test  -­‐v  test/users.sql test/users.sql  ..   ok

     1  -­‐  Table  users  should  exist 1..1 ok All  tests  successful. Files=1,  Tests=1,    1  wallclock  secs Result:  PASS > Make Users >    emacs  test/users.sql >
  460. SET  client_min_messages  TO  warning;   CREATE  EXTENSION  IF  NOT  EXISTS

     pgtap;   RESET  client_min_messages;   ! BEGIN;   SELECT  no_plan();   -­‐-­‐  SELECT  plan(1);   ! SET  search_path  TO  flipr,public;   SELECT  has_table(  'users'  ); test/users.sql Columnist SELECT  finish();   ROLLBACK;
  461. SET  client_min_messages  TO  warning;   CREATE  EXTENSION  IF  NOT  EXISTS

     pgtap;   RESET  client_min_messages;   ! BEGIN;   SELECT  no_plan();   -­‐-­‐  SELECT  plan(1);   ! SET  search_path  TO  flipr,public;   SELECT  has_table(  'users'  ); SELECT  has_column(  'users',  'nickname'    ); SELECT  has_column(  'users',  'password'    ); SELECT  has_column(  'users',  'timestamp'  ); test/users.sql Columnist SELECT  finish();   ROLLBACK;
  462. Dead Again >

  463.    pg_prove  -­‐d  flipr_test  -­‐v  test/users.sql test/users.sql  ..   ok

     1  -­‐  Table  users  should  exist ok  2  -­‐  Column  users.nickname  should  exist not  ok  3  -­‐  Column  users.password  should  exist #  Failed  test  3:  "Column  users.password  should  exist" not  ok  4  -­‐  Column  users."timestamp"  should  exist #  Failed  test  4:  "Column  users."timestamp"  should  exist" 1..4 #  Looks  like  you  failed  2  tests  of  4 Failed  2/4  subtests   Test  Summary  Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ test/users.sql  (Wstat:  0  Tests:  4  Failed:  2)    Failed  tests:    3-­‐4 Files=1,  Tests=4,    0  wallclock  secs Result:  FAIL Dead Again >
  464.    pg_prove  -­‐d  flipr_test  -­‐v  test/users.sql test/users.sql  ..   ok

     1  -­‐  Table  users  should  exist ok  2  -­‐  Column  users.nickname  should  exist not  ok  3  -­‐  Column  users.password  should  exist #  Failed  test  3:  "Column  users.password  should  exist" not  ok  4  -­‐  Column  users."timestamp"  should  exist #  Failed  test  4:  "Column  users."timestamp"  should  exist" 1..4 #  Looks  like  you  failed  2  tests  of  4 Failed  2/4  subtests   Test  Summary  Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ test/users.sql  (Wstat:  0  Tests:  4  Failed:  2)    Failed  tests:    3-­‐4 Files=1,  Tests=4,    0  wallclock  secs Result:  FAIL Dead Again > Guess we should add them.
  465. MOAR Deploy >

  466. >  emacs  deploy/users.sql > MOAR Deploy >

  467. -­‐-­‐  Deploy  users   -­‐-­‐  requires:  appschema   ! BEGIN;

      ! SET  client_min_messages  =  'warning';   CREATE  TABLE  flipr.users  (          nickname    TEXT deploy/users.sq deploy/users.sql );   ! COMMIT;
  468. -­‐-­‐  Deploy  users   -­‐-­‐  requires:  appschema   ! BEGIN;

      ! SET  client_min_messages  =  'warning';   CREATE  TABLE  flipr.users  (          nickname    TEXT                                    ,        password    TEXT,        timestamp  TIMESTAMPTZ deploy/users.sq deploy/users.sql );   ! COMMIT;
  469. >  emacs  deploy/users.sql   > Update Verify >

  470. >  emacs  deploy/users.sql   > Update Verify >    emacs

     verify/users.sql >
  471. -­‐-­‐  Verify  users   ! BEGIN;   ! SELECT  nickname

         FROM  flipr.users    WHERE  FALSE;   ! COMMIT; verify/users.sq verify/users.sql
  472. -­‐-­‐  Verify  users   ! BEGIN;   ! SELECT  nickname

         FROM  flipr.users    WHERE  FALSE;   ! COMMIT; ,  password,  timestamp verify/users.sq verify/users.sql
  473. Revert Overhead >  emacs  deploy/users.sql   >  emacs  verify/users.sql  

    >
  474. Revert Overhead    sqitch  revert  -­‐-­‐to  @HEAD^  -­‐y Reverting  changes

     to  appschema  from  flipr_test    -­‐  users  ..  ok > >  emacs  deploy/users.sql   >  emacs  verify/users.sql   >
  475. Revert Overhead    sqitch  revert  -­‐-­‐to  @HEAD^  -­‐y Reverting  changes

     to  appschema  from  flipr_test    -­‐  users  ..  ok > Yes, really. >  emacs  deploy/users.sql   >  emacs  verify/users.sql   >
  476. Revert Overhead    sqitch  revert  -­‐-­‐to  @HEAD^  -­‐y Reverting  changes

     to  appschema  from  flipr_test    -­‐  users  ..  ok > >  emacs  deploy/users.sql   >  emacs  verify/users.sql   >
  477. Revert Overhead    sqitch  revert  -­‐-­‐to  @HEAD^  -­‐y Reverting  changes

     to  appschema  from  flipr_test    -­‐  users  ..  ok > Remove >  emacs  deploy/users.sql   >  emacs  verify/users.sql   >
  478. Revert Overhead    sqitch  revert  -­‐-­‐to  @HEAD^  -­‐y Reverting  changes

     to  appschema  from  flipr_test    -­‐  users  ..  ok > >  emacs  deploy/users.sql   >  emacs  verify/users.sql   > What’s that?
  479. Sqitch Tags antisocial network

  480. Sqitch Tags Start with @ antisocial network

  481. Sqitch Tags Start with @ To distinguish from changes antisocial

    network
  482. Sqitch Tags Start with @ To distinguish from changes Two

    symbolic tags: antisocial network
  483. Sqitch Tags Start with @ To distinguish from changes Two

    symbolic tags: @HEAD Last change antisocial network
  484. Sqitch Tags Start with @ To distinguish from changes Two

    symbolic tags: @HEAD Last change @ROOT First change antisocial network
  485. Sqitch Tags Start with @ To distinguish from changes Two

    symbolic tags: @HEAD Last change @ROOT First change Two modifiers: antisocial network
  486. Sqitch Tags Start with @ To distinguish from changes Two

    symbolic tags: @HEAD Last change @ROOT First change Two modifiers: ^ Previous change antisocial network
  487. Sqitch Tags Start with @ To distinguish from changes Two

    symbolic tags: @HEAD Last change @ROOT First change Two modifiers: ^ Previous change ~ Following change antisocial network
  488. Specifying Changes antisocial network

  489. Specifying Changes users Change named “users” antisocial network

  490. Specifying Changes users Change named “users” @HEAD^ Second to last

    change antisocial network
  491. Specifying Changes users Change named “users” @HEAD^ Second to last

    change users^ Change before users antisocial network
  492. Specifying Changes users Change named “users” @HEAD^ Second to last

    change users^ Change before users @ROOT~ Second change antisocial network
  493. Specifying Changes users Change named “users” @HEAD^ Second to last

    change users^ Change before users @ROOT~ Second change appschema~ Change after appschema antisocial network
  494. Specifying Changes users Change named “users” @HEAD^ Second to last

    change users^ Change before users @ROOT~ Second change appschema~ Change after appschema @HEAD^^ Third to last change antisocial network
  495. Specifying Changes users Change named “users” @HEAD^ Second to last

    change users^ Change before users @ROOT~ Second change appschema~ Change after appschema @HEAD^^ Third to last change users~4 4th change after antisocial network
  496. >    sqitch  revert  -­‐-­‐to  @HEAD^  -­‐y   Reverting  changes

     to  appschema  from  flipr_test      -­‐  users  ..  ok   > Whither Users >
  497. >    sqitch  revert  -­‐-­‐to  @HEAD^  -­‐y   Reverting  changes

     to  appschema  from  flipr_test      -­‐  users  ..  ok   > Whither Users > >  psql  -­‐d  flipr_test  -­‐c  '\d  flipr.users' Did  not  find  any  relation  named  "flipr.users". >
  498. >    sqitch  revert  -­‐-­‐to  @HEAD^  -­‐y   Reverting  changes

     to  appschema  from  flipr_test      -­‐  users  ..  ok   >    sqitch  status #  On  database  flipr_test #  Project:    flipr #  Change:      e01feba4bb79607339a13981574855b6e2aa7526 #  Name:          appschema #  Deployed:  2014-­‐01-­‐07  16:13:50  -­‐0800 #  By:              David  E.  Wheeler  <david@justatheory.com> #   Undeployed  change:    *  users Whither Users > >  psql  -­‐d  flipr_test  -­‐c  '\d  flipr.users' Did  not  find  any  relation  named  "flipr.users". >
  499. Whither Users >

  500. >  sqitch  verify Verifying  flipr_test    *  appschema  ..  ok

    Undeployed  change:    *  users Verify  successful > Whither Users >
  501. Back At It >

  502.    sqitch  deploy Deploying  changes  to  flipr_test    +  users

     ..  ok > Back At It >
  503.    sqitch  deploy Deploying  changes  to  flipr_test    +  users

     ..  ok > Back At It > Add
  504.    sqitch  deploy Deploying  changes  to  flipr_test    +  users

     ..  ok > Back At It >    pg_prove  -­‐d  flipr_test  -­‐v  test/users.sql test/users.sql  ..   ok  1  -­‐  Table  users  should  exist ok  2  -­‐  Column  users.nickname  should  exist ok  3  -­‐  Column  users.password  should  exist ok  4  -­‐  Column  users."timestamp"  should  exist 1..4 ok All  tests  successful. Files=1,  Tests=4,    0  wallclock  secs Result:  PASS >
  505.    sqitch  deploy Deploying  changes  to  flipr_test    +  users

     ..  ok > Back At It >    pg_prove  -­‐d  flipr_test  -­‐v  test/users.sql test/users.sql  ..   ok  1  -­‐  Table  users  should  exist ok  2  -­‐  Column  users.nickname  should  exist ok  3  -­‐  Column  users.password  should  exist ok  4  -­‐  Column  users."timestamp"  should  exist 1..4 ok All  tests  successful. Files=1,  Tests=4,    0  wallclock  secs Result:  PASS > Woot!
  506.    sqitch  deploy Deploying  changes  to  flipr_test    +  users

     ..  ok > Back At It >    pg_prove  -­‐d  flipr_test  -­‐v  test/users.sql test/users.sql  ..   ok  1  -­‐  Table  users  should  exist ok  2  -­‐  Column  users.nickname  should  exist ok  3  -­‐  Column  users.password  should  exist ok  4  -­‐  Column  users."timestamp"  should  exist 1..4 ok All  tests  successful. Files=1,  Tests=4,    0  wallclock  secs Result:  PASS >    emacs  test/users.sql
  507. SET  search_path  =  public,tap;   ! BEGIN;   SELECT  no_plan();

      -­‐-­‐  SELECT  plan(1);   ! SELECT  has_table(    'users'  ); SELECT  has_column(                'users',  'timestamp'  );   test/users.sql SELECT  has_column(                'users',  'nickname'  ); SELECT  has_column(                'users',  'password'  ); SELECT  finish();   ROLLBACK;
  508. SET  search_path  =  public,tap;   ! BEGIN;   SELECT  no_plan();

      -­‐-­‐  SELECT  plan(1);   ! SELECT  has_table(    'users'  ); SELECT  has_column(                'users',  'timestamp'  );   test/users.sql SELECT  has_column(                'users',  'nickname'  ); SELECT  has_column(                'users',  'password'  ); SELECT  has_pk(          'users'  ); SELECT  finish();   ROLLBACK;
  509. SELECT  col_type_is(              'users',  'nickname',

     'text'  ); SELECT  col_hasnt_default(  'users',  'nickname'  ); SELECT  col_is_pk(                  'users',  'nickname'  ); SET  search_path  =  public,tap;   ! BEGIN;   SELECT  no_plan();   -­‐-­‐  SELECT  plan(1);   ! SELECT  has_table(    'users'  ); SELECT  has_column(                'users',  'timestamp'  );   test/users.sql SELECT  has_column(                'users',  'nickname'  ); SELECT  has_column(                'users',  'password'  ); SELECT  has_pk(          'users'  ); SELECT  finish();   ROLLBACK;
  510. SELECT  col_type_is(              'users',  'nickname',

     'text'  ); SELECT  col_hasnt_default(  'users',  'nickname'  ); SELECT  col_is_pk(                  'users',  'nickname'  ); SET  search_path  =  public,tap;   ! BEGIN;   SELECT  no_plan();   -­‐-­‐  SELECT  plan(1);   ! SELECT  has_table(    'users'  ); SELECT  has_column(                'users',  'timestamp'  );   test/users.sql SELECT  has_column(                'users',  'nickname'  ); SELECT  has_column(                'users',  'password'  ); SELECT  has_pk(          'users'  ); SELECT  col_type_is(              'users',  'password',  'text'  ); SELECT  col_not_null(            'users',  'password'  ); SELECT  col_hasnt_default(  'users',  'password'  ); SELECT  finish();   ROLLBACK;
  511. SELECT  col_type_is(              'users',  'nickname',

     'text'  ); SELECT  col_hasnt_default(  'users',  'nickname'  ); SELECT  col_is_pk(                  'users',  'nickname'  ); SET  search_path  =  public,tap;   ! BEGIN;   SELECT  no_plan();   -­‐-­‐  SELECT  plan(1);   ! SELECT  has_table(    'users'  ); SELECT  has_column(                'users',  'timestamp'  );   test/users.sql SELECT  has_column(                'users',  'nickname'  ); SELECT  has_column(                'users',  'password'  ); SELECT  has_pk(          'users'  ); SELECT  col_type_is('users',  'timestamp',  'timestamp  with  time  zone'); SELECT  col_not_null(            'users',  'timestamp'  ); SELECT  col_has_default(      'users',  'timestamp'  ); SELECT  col_default_is(        'users',  'timestamp',  'now()'  ); SELECT  col_type_is(              'users',  'password',  'text'  ); SELECT  col_not_null(            'users',  'password'  ); SELECT  col_hasnt_default(  'users',  'password'  ); SELECT  finish();   ROLLBACK;
  512. Columny >

  513. >  pg_prove  -­‐d  flipr_test  test/users.sql test/users.sql  ..  1/?   #

     Failed  test  2:  "Table  users  should  have  a  primary  key" #  Failed  test  6:  "Column  users(nickname)  should  be  a  primary  key" #                  have:  NULL #                  want:  {nickname} #  Failed  test  9:  "Column  users.password  should  be  NOT  NULL" #  Failed  test  13:  "Column  users."timestamp"  should  be  NOT  NULL" #  Failed  test  14:  "Column  users."timestamp"  should  have  a  default" #  Failed  test  15:  "Column  users."timestamp"  should  default  to  'now()'" #          Column  users."timestamp"  has  no  default #  Looks  like  you  failed  6  tests  of  15 test/users.sql  ..  Failed  6/15  subtests   Test  Summary  Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ test/users.sql  (Wstat:  0  Tests:  15  Failed:  6)    Failed  tests:    2,  6,  9,  13-­‐15 Files=1,  Tests=15,    0  wallclock  secs Result:  FAIL Columny >
  514. >  pg_prove  -­‐d  flipr_test  test/users.sql test/users.sql  ..  1/?   #

     Failed  test  2:  "Table  users  should  have  a  primary  key" #  Failed  test  6:  "Column  users(nickname)  should  be  a  primary  key" #                  have:  NULL #                  want:  {nickname} #  Failed  test  9:  "Column  users.password  should  be  NOT  NULL" #  Failed  test  13:  "Column  users."timestamp"  should  be  NOT  NULL" #  Failed  test  14:  "Column  users."timestamp"  should  have  a  default" #  Failed  test  15:  "Column  users."timestamp"  should  default  to  'now()'" #          Column  users."timestamp"  has  no  default #  Looks  like  you  failed  6  tests  of  15 test/users.sql  ..  Failed  6/15  subtests   Test  Summary  Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ test/users.sql  (Wstat:  0  Tests:  15  Failed:  6)    Failed  tests:    2,  6,  9,  13-­‐15 Files=1,  Tests=15,    0  wallclock  secs Result:  FAIL Columny > Let’s make it so.
  515. User Typography >

  516.    emacs  deploy/users.sql > User Typography >

  517. -­‐-­‐  Deploy  users   -­‐-­‐  requires:  appschema   ! BEGIN;

      ! SET  client_min_messages  =  'warning';   CREATE  TABLE  flipr.users  (          nickname    TEXT          password    TEXT          timestamp  TIMESTAMPTZ   );   ! COMMIT; deploy/users.sq deploy/users.sql , ,
  518. -­‐-­‐  Deploy  users   -­‐-­‐  requires:  appschema   ! BEGIN;

      ! SET  client_min_messages  =  'warning';   CREATE  TABLE  flipr.users  (          nickname    TEXT          password    TEXT          timestamp  TIMESTAMPTZ   );   ! COMMIT; deploy/users.sq deploy/users.sql ,                PRIMARY  KEY,
  519. -­‐-­‐  Deploy  users   -­‐-­‐  requires:  appschema   ! BEGIN;

      ! SET  client_min_messages  =  'warning';   CREATE  TABLE  flipr.users  (          nickname    TEXT          password    TEXT          timestamp  TIMESTAMPTZ   );   ! COMMIT; deploy/users.sq deploy/users.sql                PRIMARY  KEY,                NOT  NULL,
  520. -­‐-­‐  Deploy  users   -­‐-­‐  requires:  appschema   ! BEGIN;

      ! SET  client_min_messages  =  'warning';   CREATE  TABLE  flipr.users  (          nickname    TEXT          password    TEXT          timestamp  TIMESTAMPTZ   );   ! COMMIT; deploy/users.sq deploy/users.sql                PRIMARY  KEY,                NOT  NULL,  NOT  NULL  DEFAULT  NOW()
  521. User Typography >  emacs  deploy/users.sql   >

  522.    sqitch  rebase  @HEAD^  -­‐y Reverting  changes  to  appschema  from

     flipr_test    -­‐  users  ..  ok Deploying  changes  to  flipr_test    +  users  ..  ok > User Typography >  emacs  deploy/users.sql   >
  523.    sqitch  rebase  @HEAD^  -­‐y Reverting  changes  to  appschema  from

     flipr_test    -­‐  users  ..  ok Deploying  changes  to  flipr_test    +  users  ..  ok > User Typography >  emacs  deploy/users.sql   >
  524.    sqitch  rebase  @HEAD^  -­‐y Reverting  changes  to  appschema  from

     flipr_test    -­‐  users  ..  ok Deploying  changes  to  flipr_test    +  users  ..  ok > User Typography >  emacs  deploy/users.sql   >
  525.    sqitch  rebase  @HEAD^  -­‐y Reverting  changes  to  appschema  from

     flipr_test    -­‐  users  ..  ok Deploying  changes  to  flipr_test    +  users  ..  ok > User Typography >  emacs  deploy/users.sql   >    pg_prove  -­‐d  flipr_test  test/users.sql test/users.sql  ..  ok         All  tests  successful. Files=1,  Tests=15,    0  wallclock  secs Result:  PASS >
  526.    sqitch  rebase  @HEAD^  -­‐y Reverting  changes  to  appschema  from

     flipr_test    -­‐  users  ..  ok Deploying  changes  to  flipr_test    +  users  ..  ok > User Typography >  emacs  deploy/users.sql   >    pg_prove  -­‐d  flipr_test  test/users.sql test/users.sql  ..  ok         All  tests  successful. Files=1,  Tests=15,    0  wallclock  secs Result:  PASS > Boom.
  527. Additives >

  528. Additives >    git  add  . >

  529. Additives >    git  add  . >    git  commit

     -­‐am  'Add  users  table.' [users  693ca89]  Add  users  table.  5  files  changed,  60  insertions(+)  create  mode  100644  deploy/users.sql  create  mode  100644  revert/users.sql  create  mode  100644  test/users.sql  create  mode  100644  verify/users.sql >
  530. Pushers >

  531. Pushers >    git  push  -­‐-­‐set-­‐upstream  origin  users Counting  objects:

     20,  done. Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (14/14),  done. Writing  objects:  100%  (15/15),  1.95  KiB,  done. Total  15  (delta  2),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git  *  [new  branch]            users  -­‐>  users Branch  users  set  up  to  track  remote  branch  users   from  origin. >
  532. Pushers >    git  push  -­‐-­‐set-­‐upstream  origin  users Counting  objects:

     20,  done. Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (14/14),  done. Writing  objects:  100%  (15/15),  1.95  KiB,  done. Total  15  (delta  2),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git  *  [new  branch]            users  -­‐>  users Branch  users  set  up  to  track  remote  branch  users   from  origin. >
  533. Pushers >    git  push  -­‐-­‐set-­‐upstream  origin  users Counting  objects:

     20,  done. Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (14/14),  done. Writing  objects:  100%  (15/15),  1.95  KiB,  done. Total  15  (delta  2),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git  *  [new  branch]            users  -­‐>  users Branch  users  set  up  to  track  remote  branch  users   from  origin. >
  534. Wash, Rinse, Repeat antisocial network

  535. Wash, Rinse, Repeat Add failing simple test antisocial network

  536. Wash, Rinse, Repeat Add failing simple test Add and deploy

    change antisocial network
  537. Wash, Rinse, Repeat Add failing simple test Add and deploy

    change Revise test antisocial network
  538. Wash, Rinse, Repeat Add failing simple test Add and deploy

    change Revise test Revise and rebase change antisocial network
  539. Wash, Rinse, Repeat Add failing simple test Add and deploy

    change Revise test Revise and rebase change Wash, Rinse, Repeat antisocial network
  540. Wash, Rinse, Repeat Add failing simple test Add and deploy

    change Revise test Revise and rebase change Wash, Rinse, Repeat Commit/Push when done antisocial network
  541. Wash, Rinse, Repeat Add failing simple test Add and deploy

    change Revise test Revise and rebase change Wash, Rinse, Repeat Commit/Push when done Breathe in, breathe out antisocial network
  542. Time to Work! antisocial network

  543. Time to Work! Prepare to hack! antisocial network

  544. Time to Work! Prepare to hack! git checkout master antisocial

    network
  545. Time to Work! Prepare to hack! git checkout master git

    branch -D users antisocial network
  546. Time to Work! Prepare to hack! git checkout master git

    branch -D users git checkout -b users antisocial network
  547. Time to Work! Prepare to hack! git checkout master git

    branch -D users git checkout -b users git reset --hard upstream/users antisocial network
  548. Time to Work! Prepare to hack! git checkout master git

    branch -D users git checkout -b users git reset --hard upstream/users git log antisocial network
  549. Time to Work! Prepare to hack! git checkout master git

    branch -D users git checkout -b users git reset --hard upstream/users git log Should be at “Add users table.” antisocial network
  550. Caution: Hard Reset Ahead

  551. Caution: Hard Reset Ahead A rare destructive Git command

  552. Caution: Hard Reset Ahead A rare destructive Git command Deletes

    HEAD snapshot
  553. Caution: Hard Reset Ahead A rare destructive Git command Deletes

    HEAD snapshot Replaces it with new snapshot
  554. Caution: Hard Reset Ahead A rare destructive Git command Deletes

    HEAD snapshot Replaces it with new snapshot Almost un-reversible
  555. Caution: Hard Reset Ahead A rare destructive Git command Deletes

    HEAD snapshot Replaces it with new snapshot Almost un-reversible Useful for starting from known point
  556. Caution: Hard Reset Ahead A rare destructive Git command Deletes

    HEAD snapshot Replaces it with new snapshot Almost un-reversible Useful for starting from known point USE WITH CAUTION!
  557. antisocial network Flip Out

  558. antisocial network Flip Out Create flips branch

  559. antisocial network Flip Out Create flips branch Create flips table

  560. antisocial network Flip Out Create flips branch Create flips table

    flip_id SERIAL PK
  561. antisocial network Flip Out Create flips branch Create flips table

    flip_id SERIAL PK nickname FK
  562. antisocial network Flip Out Create flips branch Create flips table

    flip_id SERIAL PK nickname FK body TEXT
  563. antisocial network Flip Out Create flips branch Create flips table

    flip_id SERIAL PK nickname FK body TEXT timestamptz
  564. antisocial network Flip Out Create flips branch Create flips table

    flip_id SERIAL PK nickname FK body TEXT timestamptz Use TDDD
  565. antisocial network Flip Out Create flips branch Create flips table

    flip_id SERIAL PK nickname FK body TEXT timestamptz Use TDDD https:/ /github.com/ theory/agile-flipr.git
  566. Functional Testing >

  567. Functional Testing    git  checkout  -­‐b  userfuncs  users Switched  to

     a  new  branch  'userfuncs' > > Branches from users
  568. Functional Testing    git  checkout  -­‐b  userfuncs  users Switched  to

     a  new  branch  'userfuncs' > >    sqitch  add  insert_user  -­‐r  users  -­‐r  appschema  \            -­‐n  'Creates  a  function  to  insert  a  user.' Created  deploy/insert_user.sql Created  revert/insert_user.sql Created  test/insert_user.sql Created  verify/insert_user.sql Added  "insert_user  [users  appschema]"  to  sqitch.plan >
  569. Functional Testing    git  checkout  -­‐b  userfuncs  users Switched  to

     a  new  branch  'userfuncs' > >    sqitch  add  insert_user  -­‐r  users  -­‐r  appschema  \            -­‐n  'Creates  a  function  to  insert  a  user.' Created  deploy/insert_user.sql Created  revert/insert_user.sql Created  test/insert_user.sql Created  verify/insert_user.sql Added  "insert_user  [users  appschema]"  to  sqitch.plan >    emacs  test/insert_user.sql >
  570. test/insert_use test/insert_user.sql

  571. test/insert_use test/insert_user.sql SET  client_min_messages  TO  warning; CREATE  EXTENSION  IF  NOT

     EXISTS  pgtap; RESET  client_min_messages; SET  search_path  TO  flipr,public;
  572. test/insert_use test/insert_user.sql SET  client_min_messages  TO  warning; CREATE  EXTENSION  IF  NOT

     EXISTS  pgtap; RESET  client_min_messages; SET  search_path  TO  flipr,public; BEGIN; -­‐-­‐  SELECT  no_plan(); SELECT  plan(11);
  573. test/insert_use test/insert_user.sql SET  client_min_messages  TO  warning; CREATE  EXTENSION  IF  NOT

     EXISTS  pgtap; RESET  client_min_messages; SET  search_path  TO  flipr,public; BEGIN; -­‐-­‐  SELECT  no_plan(); SELECT  plan(11);
  574. test/insert_use SELECT  plan(11);

  575. test/insert_use SELECT  plan(11); SELECT  has_function(  'insert_user'  ); SELECT  has_function(  

         'insert_user',  ARRAY['text',  'text'] ); SELECT  function_lang_is(        'insert_user',  ARRAY['text',  'text'],        'sql' ); SELECT  function_returns(        'insert_user',  ARRAY['text',  'text'],        'void' ); SELECT  volatility_is(        'insert_user',  ARRAY['text',  'text'],        'volatile' );
  576. test/insert_use SELECT  plan(11); SELECT  has_function(  'insert_user'  ); SELECT  has_function(  

         'insert_user',  ARRAY['text',  'text'] ); SELECT  function_lang_is(        'insert_user',  ARRAY['text',  'text'],        'sql' ); SELECT  function_returns(        'insert_user',  ARRAY['text',  'text'],        'void' ); SELECT  volatility_is(        'insert_user',  ARRAY['text',  'text'],        'volatile' );
  577. test/insert_use SELECT  plan(11); SELECT  has_function(  'insert_user'  ); SELECT  has_function(  

         'insert_user',  ARRAY['text',  'text'] ); SELECT  function_lang_is(        'insert_user',  ARRAY['text',  'text'],        'sql' ); SELECT  function_returns(        'insert_user',  ARRAY['text',  'text'],        'void' ); SELECT  volatility_is(        'insert_user',  ARRAY['text',  'text'],        'volatile' );
  578. test/insert_use SELECT  plan(11); SELECT  has_function(  'insert_user'  ); SELECT  has_function(  

         'insert_user',  ARRAY['text',  'text'] ); SELECT  function_lang_is(        'insert_user',  ARRAY['text',  'text'],        'sql' ); SELECT  function_returns(        'insert_user',  ARRAY['text',  'text'],        'void' ); SELECT  volatility_is(        'insert_user',  ARRAY['text',  'text'],        'volatile' );
  579. test/insert_use SELECT  plan(11); SELECT  has_function(  'insert_user'  ); SELECT  has_function(  

         'insert_user',  ARRAY['text',  'text'] ); SELECT  function_lang_is(        'insert_user',  ARRAY['text',  'text'],        'sql' ); SELECT  function_returns(        'insert_user',  ARRAY['text',  'text'],        'void' ); SELECT  volatility_is(        'insert_user',  ARRAY['text',  'text'],        'volatile' );
  580. test/insert_use test/insert_user.sql        'volatile'   );

  581. test/insert_use test/insert_user.sql        'volatile'   ); SELECT  lives_ok(

           $$  SELECT  insert_user('theory',  'foo')  $$,        'Insert  a  user' ); SELECT  row_eq(      'SELECT  *  FROM  users',      ROW('theory',  md5('foo'),  NOW())::users,      'The  user  should  have  been  inserted' );
  582. test/insert_use test/insert_user.sql        'volatile'   ); SELECT  lives_ok(

           $$  SELECT  insert_user('theory',  'foo')  $$,        'Insert  a  user' ); SELECT  row_eq(      'SELECT  *  FROM  users',      ROW('theory',  md5('foo'),  NOW())::users,      'The  user  should  have  been  inserted' );
  583. test/insert_use test/insert_user.sql        'volatile'   ); SELECT  lives_ok(

           $$  SELECT  insert_user('theory',  'foo')  $$,        'Insert  a  user' ); SELECT  row_eq(      'SELECT  *  FROM  users',      ROW('theory',  md5('foo'),  NOW())::users,      'The  user  should  have  been  inserted' );
  584. test/insert_use test/insert_user.sql        'volatile'   ); SELECT  lives_ok(

           $$  SELECT  insert_user('theory',  'foo')  $$,        'Insert  a  user' ); SELECT  row_eq(      'SELECT  *  FROM  users',      ROW('theory',  md5('foo'),  NOW())::users,      'The  user  should  have  been  inserted' );
  585. test/insert_use test/insert_user.sql        'volatile'   ); SELECT  lives_ok(

           $$  SELECT  insert_user('theory',  'foo')  $$,        'Insert  a  user' ); SELECT  row_eq(      'SELECT  *  FROM  users',      ROW('theory',  md5('foo'),  NOW())::users,      'The  user  should  have  been  inserted' );
  586. test/insert_use test/insert_user.sql      'The  user  should  have  been  inserted'

      );
  587. test/insert_use test/insert_user.sql      'The  user  should  have  been  inserted'

      ); SELECT  lives_ok(        $$  SELECT  insert_user('strongrrl',  'w00t')  $$,        'Insert  another  user' ); SELECT  bag_eq(        'SELECT  *  FROM  users',        $$  VALUES                ('theory',        md5('foo'),    NOW()),                ('strongrrl',  md5('w00t'),  NOW())        $$,        'Both  users  should  be  present' );
  588. test/insert_use test/insert_user.sql      'The  user  should  have  been  inserted'

      ); SELECT  lives_ok(        $$  SELECT  insert_user('strongrrl',  'w00t')  $$,        'Insert  another  user' ); SELECT  bag_eq(        'SELECT  *  FROM  users',        $$  VALUES                ('theory',        md5('foo'),    NOW()),                ('strongrrl',  md5('w00t'),  NOW())        $$,        'Both  users  should  be  present' );
  589. test/insert_use test/insert_user.sql      'The  user  should  have  been  inserted'

      ); SELECT  lives_ok(        $$  SELECT  insert_user('strongrrl',  'w00t')  $$,        'Insert  another  user' ); SELECT  bag_eq(        'SELECT  *  FROM  users',        $$  VALUES                ('theory',        md5('foo'),    NOW()),                ('strongrrl',  md5('w00t'),  NOW())        $$,        'Both  users  should  be  present' ); Includes dupes
  590. test/insert_use test/insert_user.sql      'The  user  should  have  been  inserted'

      ); SELECT  lives_ok(        $$  SELECT  insert_user('strongrrl',  'w00t')  $$,        'Insert  another  user' ); SELECT  bag_eq(        'SELECT  *  FROM  users',        $$  VALUES                ('theory',        md5('foo'),    NOW()),                ('strongrrl',  md5('w00t'),  NOW())        $$,        'Both  users  should  be  present' );
  591. test/insert_use test/insert_user.sql      'The  user  should  have  been  inserted'

      ); SELECT  lives_ok(        $$  SELECT  insert_user('strongrrl',  'w00t')  $$,        'Insert  another  user' ); SELECT  bag_eq(        'SELECT  *  FROM  users',        $$  VALUES                ('theory',        md5('foo'),    NOW()),                ('strongrrl',  md5('w00t'),  NOW())        $$,        'Both  users  should  be  present' );
  592. test/insert_use        'Both  users  should  be  present'  

    );
  593. SELECT  throws_ok(        $$  SELECT  insert_user('theory',  'ha-­‐ha')  $$,

           23505,  -­‐-­‐  duplicate  key  violation        NULL,    -­‐-­‐  localized  error  message        'Should  get  an  error  for  duplicate  nickname' ); SELECT  bag_eq(        'SELECT  *  FROM  users',        $$  VALUES                ('theory',        md5('foo'),    NOW()),                ('strongrrl',  md5('w00t'),  NOW())        $$,        'Should  still  have  just  the  two  users' ); test/insert_use        'Both  users  should  be  present'   );
  594. SELECT  throws_ok(        $$  SELECT  insert_user('theory',  'ha-­‐ha')  $$,

           23505,  -­‐-­‐  duplicate  key  violation        NULL,    -­‐-­‐  localized  error  message        'Should  get  an  error  for  duplicate  nickname' ); SELECT  bag_eq(        'SELECT  *  FROM  users',        $$  VALUES                ('theory',        md5('foo'),    NOW()),                ('strongrrl',  md5('w00t'),  NOW())        $$,        'Should  still  have  just  the  two  users' ); test/insert_use        'Both  users  should  be  present'   );
  595. SELECT  throws_ok(        $$  SELECT  insert_user('theory',  'ha-­‐ha')  $$,

           23505,  -­‐-­‐  duplicate  key  violation        NULL,    -­‐-­‐  localized  error  message        'Should  get  an  error  for  duplicate  nickname' ); SELECT  bag_eq(        'SELECT  *  FROM  users',        $$  VALUES                ('theory',        md5('foo'),    NOW()),                ('strongrrl',  md5('w00t'),  NOW())        $$,        'Should  still  have  just  the  two  users' ); test/insert_use        'Both  users  should  be  present'   ); Appendix A
  596. SELECT  throws_ok(        $$  SELECT  insert_user('theory',  'ha-­‐ha')  $$,

           23505,  -­‐-­‐  duplicate  key  violation        NULL,    -­‐-­‐  localized  error  message        'Should  get  an  error  for  duplicate  nickname' ); SELECT  bag_eq(        'SELECT  *  FROM  users',        $$  VALUES                ('theory',        md5('foo'),    NOW()),                ('strongrrl',  md5('w00t'),  NOW())        $$,        'Should  still  have  just  the  two  users' ); test/insert_use        'Both  users  should  be  present'   );
  597. SELECT  throws_ok(        $$  SELECT  insert_user('theory',  'ha-­‐ha')  $$,

           23505,  -­‐-­‐  duplicate  key  violation        NULL,    -­‐-­‐  localized  error  message        'Should  get  an  error  for  duplicate  nickname' ); SELECT  bag_eq(        'SELECT  *  FROM  users',        $$  VALUES                ('theory',        md5('foo'),    NOW()),                ('strongrrl',  md5('w00t'),  NOW())        $$,        'Should  still  have  just  the  two  users' ); test/insert_use        'Both  users  should  be  present'   );
  598. SELECT  throws_ok(        $$  SELECT  insert_user('theory',  'ha-­‐ha')  $$,

           23505,  -­‐-­‐  duplicate  key  violation        NULL,    -­‐-­‐  localized  error  message        'Should  get  an  error  for  duplicate  nickname' ); SELECT  bag_eq(        'SELECT  *  FROM  users',        $$  VALUES                ('theory',        md5('foo'),    NOW()),                ('strongrrl',  md5('w00t'),  NOW())        $$,        'Should  still  have  just  the  two  users' ); test/insert_use        'Both  users  should  be  present'   );
  599. SELECT  throws_ok(        $$  SELECT  insert_user('theory',  'ha-­‐ha')  $$,

           23505,  -­‐-­‐  duplicate  key  violation        NULL,    -­‐-­‐  localized  error  message        'Should  get  an  error  for  duplicate  nickname' ); SELECT  bag_eq(        'SELECT  *  FROM  users',        $$  VALUES                ('theory',        md5('foo'),    NOW()),                ('strongrrl',  md5('w00t'),  NOW())        $$,        'Should  still  have  just  the  two  users' ); test/insert_use        'Both  users  should  be  present'   ); SELECT  finish(); ROLLBACK;
  600. Functional Testing    emacs  test/insert_user.sql   > >

  601. Functional Testing    emacs  test/insert_user.sql   > >    emacs

     deploy/insert_user.sql >
  602. deploy/insert_u deploy/insert_user.sql -­‐-­‐  Deploy  insert_user   -­‐-­‐  requires:  users  

    -­‐-­‐  requires:  appschema   ! BEGIN; -­‐-­‐  XXX  Add  DDLs  here. COMMIT;
  603. deploy/insert_u deploy/insert_user.sql -­‐-­‐  Deploy  insert_user   -­‐-­‐  requires:  users  

    -­‐-­‐  requires:  appschema   ! BEGIN; CREATE  OR  REPLACE  FUNCTION  flipr.insert_user(        nickname  TEXT,        password  TEXT )  RETURNS  VOID  LANGUAGE  SQL  SECURITY  DEFINER  AS  $$        INSERT  INTO  flipr.users  VALUES($1,  md5($2)); $$; COMMIT;
  604. Functional Testing    emacs  deploy/insert_user.sql   > >

  605. Functional Testing    emacs  deploy/insert_user.sql   > >    emacs

     revert/insert_user.sql >
  606. revert/insert_u revert/insert_user.sql -­‐-­‐  Revert  insert_user   ! BEGIN;   !

    ! ! COMMIT; -­‐-­‐  XXX  Add  DDLs  here.
  607. revert/insert_u revert/insert_user.sql -­‐-­‐  Revert  insert_user   ! BEGIN;   !

    ! ! COMMIT; DROP  FUNCTION  flipr.insert_user(TEXT,  TEXT);
  608. Functional Testing    emacs  revert/insert_user.sql   > >

  609. Functional Testing    emacs  revert/insert_user.sql   > >    emacs

     verify/insert_user.sql >
  610. verify/insert_u verify/insert_user.sql -­‐-­‐  Verify  insert_user   ! BEGIN; -­‐-­‐  XXX

     Add  DDLs  here. ROLLBACK;
  611. verify/insert_u verify/insert_user.sql -­‐-­‐  Verify  insert_user   ! BEGIN; SELECT  has_function_privilege(

           'flipr.insert_user(text,  text)',        'execute' ); ROLLBACK;
  612. verify/insert_u verify/insert_user.sql -­‐-­‐  Verify  insert_user   ! BEGIN; SELECT  has_function_privilege(

           'flipr.insert_user(text,  text)',        'execute' ); ROLLBACK; Convenient!
  613. We Good?    emacs  verify/insert_user.sql   > >

  614. We Good?    emacs  verify/insert_user.sql   > >    sqitch

     deploy Deploying  changes  to  flipr_test    +  insert_user  ..  ok >
  615. We Good?    emacs  verify/insert_user.sql   > >    sqitch

     deploy Deploying  changes  to  flipr_test    +  insert_user  ..  ok >    pg_prove  -­‐d  flipr_test  test/*.sql                     test/appschema.sql  ....  ok       test/insert_user.sql  ..  ok           test/users.sql  ........  ok         All  tests  successful. Files=3,  Tests=27,    0  wallclock  secs Result:  PASS >
  616. Commitment >

  617.    git  add  . >  git  commit  -­‐m  'Add  `insert_user()`.'

    [userfuncs  e1c7769]  Add  `insert_user()`.  5  files  changed,  101  insertions(+)  create  mode  100644  deploy/insert_user.sql  create  mode  100644  revert/insert_user.sql  create  mode  100644  test/insert_user.sql  create  mode  100644  verify/insert_user.sql > Commitment >
  618. Push It Real Good… >

  619.    git  push  origin  -­‐-­‐set-­‐upstream  userfuncs Counting  objects:  17,  done.

    Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (11/11),  done. Writing  objects:  100%  (11/11),  1.91  KiB,  done. Total  11  (delta  1),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git  *  [new  branch]            userfuncs  -­‐>  userfuncs Branch  userfuncs  set  up  to  track  remote  branch   userfuncs  from  origin. > Push It Real Good… >
  620.    git  push  origin  -­‐-­‐set-­‐upstream  userfuncs Counting  objects:  17,  done.

    Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (11/11),  done. Writing  objects:  100%  (11/11),  1.91  KiB,  done. Total  11  (delta  1),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git  *  [new  branch]            userfuncs  -­‐>  userfuncs Branch  userfuncs  set  up  to  track  remote  branch   userfuncs  from  origin. > Push It Real Good… >
  621.    git  push  origin  -­‐-­‐set-­‐upstream  userfuncs Counting  objects:  17,  done.

    Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (11/11),  done. Writing  objects:  100%  (11/11),  1.91  KiB,  done. Total  11  (delta  1),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git  *  [new  branch]            userfuncs  -­‐>  userfuncs Branch  userfuncs  set  up  to  track  remote  branch   userfuncs  from  origin. > Push It Real Good… >
  622. Reset, Mes Amis! antisocial network

  623. Reset, Mes Amis! git checkout users antisocial network

  624. Reset, Mes Amis! git checkout users git reset --hard upstream/users

    antisocial network
  625. Reset, Mes Amis! git checkout users git reset --hard upstream/users

    git checkout -b userfuncs antisocial network
  626. Reset, Mes Amis! git checkout users git reset --hard upstream/users

    git checkout -b userfuncs git reset --hard insert_user antisocial network
  627. antisocial network None Shall Pass

  628. antisocial network None Shall Pass Create change_pass()

  629. antisocial network None Shall Pass Create change_pass() Params:

  630. antisocial network None Shall Pass Create change_pass() Params: nickname

  631. antisocial network None Shall Pass Create change_pass() Params: nickname old_pass

  632. antisocial network None Shall Pass Create change_pass() Params: nickname old_pass

    new_pass
  633. antisocial network None Shall Pass Create change_pass() Params: nickname old_pass

    new_pass Only update if old pass correct
  634. antisocial network None Shall Pass Create change_pass() Params: nickname old_pass

    new_pass Only update if old pass correct Use TDDD
  635. antisocial network None Shall Pass Create change_pass() Params: nickname old_pass

    new_pass Only update if old pass correct Use TDDD https:/ /github.com/ theory/agile-flipr.git
  636. Resets >

  637. Resets > My solution >  git  reset  -­‐-­‐hard  upstream/change_pass HEAD

     is  now  at  048017a  Add  `change_pass()`.  
  638. Resets > >  sqitch  checkout  master  -­‐y Last  change  before

     the  branches  diverged:  appschema Reverting  changes  to  appschema  from  flipr_test    -­‐  change_pass  ..  ok    -­‐  insert_user  ..  ok    -­‐  users  ........  ok Switched  to  branch  'master' Nothing  to  deploy  (up-­‐to-­‐date) > >  git  reset  -­‐-­‐hard  upstream/change_pass HEAD  is  now  at  048017a  Add  `change_pass()`.  
  639. Resets > >  sqitch  checkout  master  -­‐y Last  change  before

     the  branches  diverged:  appschema Reverting  changes  to  appschema  from  flipr_test    -­‐  change_pass  ..  ok    -­‐  insert_user  ..  ok    -­‐  users  ........  ok Switched  to  branch  'master' Nothing  to  deploy  (up-­‐to-­‐date) > >  git  reset  -­‐-­‐hard  upstream/change_pass HEAD  is  now  at  048017a  Add  `change_pass()`.  
  640. Resets > >  sqitch  checkout  master  -­‐y Last  change  before

     the  branches  diverged:  appschema Reverting  changes  to  appschema  from  flipr_test    -­‐  change_pass  ..  ok    -­‐  insert_user  ..  ok    -­‐  users  ........  ok Switched  to  branch  'master' Nothing  to  deploy  (up-­‐to-­‐date) > >  git  reset  -­‐-­‐hard  upstream/change_pass HEAD  is  now  at  048017a  Add  `change_pass()`.  
  641. Resets > >  sqitch  checkout  master  -­‐y Last  change  before

     the  branches  diverged:  appschema Reverting  changes  to  appschema  from  flipr_test    -­‐  change_pass  ..  ok    -­‐  insert_user  ..  ok    -­‐  users  ........  ok Switched  to  branch  'master' Nothing  to  deploy  (up-­‐to-­‐date) > >  git  reset  -­‐-­‐hard  upstream/change_pass HEAD  is  now  at  048017a  Add  `change_pass()`.  
  642. Resets > >  sqitch  checkout  master  -­‐y Last  change  before

     the  branches  diverged:  appschema Reverting  changes  to  appschema  from  flipr_test    -­‐  change_pass  ..  ok    -­‐  insert_user  ..  ok    -­‐  users  ........  ok Switched  to  branch  'master' Nothing  to  deploy  (up-­‐to-­‐date) > >  git  reset  -­‐-­‐hard  upstream/change_pass HEAD  is  now  at  048017a  Add  `change_pass()`.  
  643. Resets > >  sqitch  checkout  master  -­‐y Last  change  before

     the  branches  diverged:  appschema Reverting  changes  to  appschema  from  flipr_test    -­‐  change_pass  ..  ok    -­‐  insert_user  ..  ok    -­‐  users  ........  ok Switched  to  branch  'master' Nothing  to  deploy  (up-­‐to-­‐date) > >  git  reset  -­‐-­‐hard  upstream/change_pass HEAD  is  now  at  048017a  Add  `change_pass()`.  
  644. Resets > >  sqitch  checkout  master  -­‐y Last  change  before

     the  branches  diverged:  appschema Reverting  changes  to  appschema  from  flipr_test    -­‐  change_pass  ..  ok    -­‐  insert_user  ..  ok    -­‐  users  ........  ok Switched  to  branch  'master' Nothing  to  deploy  (up-­‐to-­‐date) >    git  reset  -­‐-­‐hard  appschema HEAD  is  now  at  e46bdf9  Add  appschema  test. > >  git  reset  -­‐-­‐hard  upstream/change_pass HEAD  is  now  at  048017a  Add  `change_pass()`.  
  645. Resets > Known good. >  sqitch  checkout  master  -­‐y Last

     change  before  the  branches  diverged:  appschema Reverting  changes  to  appschema  from  flipr_test    -­‐  change_pass  ..  ok    -­‐  insert_user  ..  ok    -­‐  users  ........  ok Switched  to  branch  'master' Nothing  to  deploy  (up-­‐to-­‐date) >    git  reset  -­‐-­‐hard  appschema HEAD  is  now  at  e46bdf9  Add  appschema  test. > >  git  reset  -­‐-­‐hard  upstream/change_pass HEAD  is  now  at  048017a  Add  `change_pass()`.  
  646. Mergers and Acquisitions >

  647.    git  merge  -­‐-­‐no-­‐ff  users  -­‐m  'Merge  branch  "users".' Merge

     made  by  the  'recursive'  strategy.  deploy/users.sql  |  13  +++++++++++++  revert/users.sql  |    7  +++++++  sqitch.plan            |    1  +  test/users.sql      |  30  ++++++++++++++++++++++++++++++  verify/users.sql  |    9  +++++++++  5  files  changed,  60  insertions(+)  create  mode  100644  deploy/users.sql  create  mode  100644  revert/users.sql  create  mode  100644  test/users.sql  create  mode  100644  verify/users.sql > Mergers and Acquisitions >
  648.    git  merge  -­‐-­‐no-­‐ff  users  -­‐m  'Merge  branch  "users".' Merge

     made  by  the  'recursive'  strategy.  deploy/users.sql  |  13  +++++++++++++  revert/users.sql  |    7  +++++++  sqitch.plan            |    1  +  test/users.sql      |  30  ++++++++++++++++++++++++++++++  verify/users.sql  |    9  +++++++++  5  files  changed,  60  insertions(+)  create  mode  100644  deploy/users.sql  create  mode  100644  revert/users.sql  create  mode  100644  test/users.sql  create  mode  100644  verify/users.sql > Mergers and Acquisitions > So far…
  649. Mergers and Acquisitions >

  650. >  git  merge  -­‐-­‐no-­‐ff  flips  -­‐m  'Merge  branch  "flips".' Merge

     made  by  the  'recursive'  strategy.  deploy/flips.sql  |  15  +++++++++++++++  revert/flips.sql  |    7  +++++++  sqitch.plan            |    1  +  test/flips.sql      |  39  +++++++++++++++++++++++++++++++++++++  verify/flips.sql  |  12  ++++++++++++  5  files  changed,  74  insertions(+)  create  mode  100644  deploy/flips.sql  create  mode  100644  revert/flips.sql  create  mode  100644  test/flips.sql  create  mode  100644  verify/flips.sql > Mergers and Acquisitions >
  651. >  git  merge  -­‐-­‐no-­‐ff  flips  -­‐m  'Merge  branch  "flips".' Merge

     made  by  the  'recursive'  strategy.  deploy/flips.sql  |  15  +++++++++++++++  revert/flips.sql  |    7  +++++++  sqitch.plan            |    1  +  test/flips.sql      |  39  +++++++++++++++++++++++++++++++++++++  verify/flips.sql  |  12  ++++++++++++  5  files  changed,  74  insertions(+)  create  mode  100644  deploy/flips.sql  create  mode  100644  revert/flips.sql  create  mode  100644  test/flips.sql  create  mode  100644  verify/flips.sql > Mergers and Acquisitions > So good…
  652. Mergers and Acquisitions >

  653. >  git  merge  -­‐-­‐no-­‐ff  userfuncs  -­‐m  'Merge  branch  "user Auto-­‐merging

     sqitch.plan CONFLICT  (content):  Merge  conflict  in  sqitch.plan Automatic  merge  failed;  fix  conflicts  and  then   commit  the  result. > Mergers and Acquisitions >
  654. >  git  merge  -­‐-­‐no-­‐ff  userfuncs  -­‐m  'Merge  branch  "user Auto-­‐merging

     sqitch.plan CONFLICT  (content):  Merge  conflict  in  sqitch.plan Automatic  merge  failed;  fix  conflicts  and  then   commit  the  result. > Mergers and Acquisitions >
  655. >  git  merge  -­‐-­‐no-­‐ff  userfuncs  -­‐m  'Merge  branch  "user Auto-­‐merging

     sqitch.plan CONFLICT  (content):  Merge  conflict  in  sqitch.plan Automatic  merge  failed;  fix  conflicts  and  then   commit  the  result. > Mergers and Acquisitions >
  656. >  git  merge  -­‐-­‐no-­‐ff  userfuncs  -­‐m  'Merge  branch  "user Auto-­‐merging

     sqitch.plan CONFLICT  (content):  Merge  conflict  in  sqitch.plan Automatic  merge  failed;  fix  conflicts  and  then   commit  the  result. > Mergers and Acquisitions > Wha???
  657. Back in Time… >

  658. Back in Time…    git  checkout  -­‐b  userfuncs  users Switched

     to  a  new  branch  'userfuncs' > >
  659. Back in Time…    git  checkout  -­‐b  userfuncs  users Switched

     to  a  new  branch  'userfuncs' > > Ah-ha!
  660. Branching Out antisocial network

  661. Branching Out users branched from master antisocial network

  662. Branching Out users branched from master flips branched from users

    antisocial network
  663. Branching Out users branched from master flips branched from users

    userfuncs branched from users antisocial network
  664. Branching Out users branched from master flips branched from users

    userfuncs branched from users users and flips merged to master antisocial network
  665. Branching Out users branched from master flips branched from users

    userfuncs branched from users users and flips merged to master userfuncs unaware of flips antisocial network
  666. Backbrancher master A

  667. Backbrancher master users A branch

  668. Backbrancher master users A B Add users table branch

  669. Backbrancher master users A B flips branch branch

  670. Backbrancher master users A B flips C Add flips table

    branch branch
  671. Backbrancher master users A B flips C userfuncs branch branch

    branch
  672. Backbrancher master users A B flips C userfuncs Add insert_user

    function D branch branch branch
  673. Backbrancher master users A B flips C userfuncs D branch

    branch branch E Add change_pass function
  674. Backbrancher master users A B flips C userfuncs B merge

    B D branch branch branch E
  675. Backbrancher master users A B flips C userfuncs B merge

    B C merge C D branch branch branch E
  676. Backbrancher master users A B flips C userfuncs B merge

    B C merge C D F merge D & E branch branch branch E
  677. Backbrancher master users A B flips C userfuncs B merge

    B C merge C D No C! F merge D & E branch branch branch E
  678. Backbrancher master users A B flips C userfuncs B merge

    B C merge C D conflict! branch branch branch E
  679. Backbrancher master users A B flips C userfuncs B merge

    B C merge C D conflict! Now what? branch branch branch E
  680. Rebase master master users A B flips C userfuncs B

    merge B C merge C branch branch branch D E
  681. Rebase master master users A B flips C userfuncs B

    merge B C merge C branch branch branch Last common with master: B
  682. Rebase master master users A B flips C userfuncs B

    merge B C merge C branch branch branch C
  683. Rebase master master users A B flips C userfuncs B

    merge B C merge C branch branch branch C D Rebased E
  684. Rebase master master users A B flips C userfuncs B

    merge B C merge C branch branch branch C D E merge D & E E
  685. \o/ Rebase master master users A B flips C userfuncs

    B merge B C merge C branch branch branch C D E merge D & E E
  686. Reset >

  687.    git  reset  -­‐-­‐hard  HEAD HEAD  is  now  at  e1cfc5d

     Merge  branch  "flips". > Reset >
  688.    git  reset  -­‐-­‐hard  HEAD HEAD  is  now  at  e1cfc5d

     Merge  branch  "flips". > Reset > Use with care!
  689.    git  reset  -­‐-­‐hard  HEAD HEAD  is  now  at  e1cfc5d

     Merge  branch  "flips". > Reset >
  690.    git  reset  -­‐-­‐hard  HEAD HEAD  is  now  at  e1cfc5d

     Merge  branch  "flips". > Reset >    git  checkout  userfuncs Switched  to  branch  'userfuncs' >
  691. Rebase >

  692. >  git  rebase  master First,  rewinding  head  to  replay  your

     work  on  top  of  it... Applying:  Add  `insert_user()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan CONFLICT  (content):  Merge  conflict  in  sqitch.plan Failed  to  merge  in  the  changes. Patch  failed  at  0001  Add  `insert_user()`. The  copy  of  the  patch  that  failed  is  found  in:      flipr-­‐db/.git/rebase-­‐apply/patch When  you  have  resolved  this  problem,  run  "git  rebase  -­‐-­‐contin If  you  prefer  to  skip  this  patch,  run  "git  rebase  -­‐-­‐skip"  ins To  check  out  the  original  branch  and  stop  rebasing,  run  "git   rebase  -­‐-­‐abort". > Rebase >
  693. >  git  rebase  master First,  rewinding  head  to  replay  your

     work  on  top  of  it... Applying:  Add  `insert_user()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan CONFLICT  (content):  Merge  conflict  in  sqitch.plan Failed  to  merge  in  the  changes. Patch  failed  at  0001  Add  `insert_user()`. The  copy  of  the  patch  that  failed  is  found  in:      flipr-­‐db/.git/rebase-­‐apply/patch When  you  have  resolved  this  problem,  run  "git  rebase  -­‐-­‐contin If  you  prefer  to  skip  this  patch,  run  "git  rebase  -­‐-­‐skip"  ins To  check  out  the  original  branch  and  stop  rebasing,  run  "git   rebase  -­‐-­‐abort". > Rebase > Back to B, apply C.
  694. >  git  rebase  master First,  rewinding  head  to  replay  your

     work  on  top  of  it... Applying:  Add  `insert_user()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan CONFLICT  (content):  Merge  conflict  in  sqitch.plan Failed  to  merge  in  the  changes. Patch  failed  at  0001  Add  `insert_user()`. The  copy  of  the  patch  that  failed  is  found  in:      flipr-­‐db/.git/rebase-­‐apply/patch When  you  have  resolved  this  problem,  run  "git  rebase  -­‐-­‐contin If  you  prefer  to  skip  this  patch,  run  "git  rebase  -­‐-­‐skip"  ins To  check  out  the  original  branch  and  stop  rebasing,  run  "git   rebase  -­‐-­‐abort". > Rebase > That’s D
  695. >  git  rebase  master First,  rewinding  head  to  replay  your

     work  on  top  of  it... Applying:  Add  `insert_user()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan CONFLICT  (content):  Merge  conflict  in  sqitch.plan Failed  to  merge  in  the  changes. Patch  failed  at  0001  Add  `insert_user()`. The  copy  of  the  patch  that  failed  is  found  in:      flipr-­‐db/.git/rebase-­‐apply/patch When  you  have  resolved  this  problem,  run  "git  rebase  -­‐-­‐contin If  you  prefer  to  skip  this  patch,  run  "git  rebase  -­‐-­‐skip"  ins To  check  out  the  original  branch  and  stop  rebasing,  run  "git   rebase  -­‐-­‐abort". > Rebase > Here comes D…
  696. >  git  rebase  master First,  rewinding  head  to  replay  your

     work  on  top  of  it... Applying:  Add  `insert_user()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan CONFLICT  (content):  Merge  conflict  in  sqitch.plan Failed  to  merge  in  the  changes. Patch  failed  at  0001  Add  `insert_user()`. The  copy  of  the  patch  that  failed  is  found  in:      flipr-­‐db/.git/rebase-­‐apply/patch When  you  have  resolved  this  problem,  run  "git  rebase  -­‐-­‐contin If  you  prefer  to  skip  this  patch,  run  "git  rebase  -­‐-­‐skip"  ins To  check  out  the  original  branch  and  stop  rebasing,  run  "git   rebase  -­‐-­‐abort". > Rebase > D’oh!
  697. >  git  rebase  master First,  rewinding  head  to  replay  your

     work  on  top  of  it... Applying:  Add  `insert_user()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan CONFLICT  (content):  Merge  conflict  in  sqitch.plan Failed  to  merge  in  the  changes. Patch  failed  at  0001  Add  `insert_user()`. The  copy  of  the  patch  that  failed  is  found  in:      flipr-­‐db/.git/rebase-­‐apply/patch When  you  have  resolved  this  problem,  run  "git  rebase  -­‐-­‐contin If  you  prefer  to  skip  this  patch,  run  "git  rebase  -­‐-­‐skip"  ins To  check  out  the  original  branch  and  stop  rebasing,  run  "git   rebase  -­‐-­‐abort". > Rebase >
  698. Wha Happen? antisocial network

  699. Wha Happen? Same conflict antisocial network

  700. Wha Happen? Same conflict Both branches modified sqitch.plan antisocial network

  701. Wha Happen? Same conflict Both branches modified sqitch.plan The same

    line! antisocial network
  702. Wha Happen? >

  703. >  git  diff diff  -­‐-­‐cc  sqitch.plan index  7526d1c,e2c966c..0000000 -­‐-­‐-­‐  a/sqitch.plan

    +++  b/sqitch.plan @@@  -­‐4,4  -­‐4,4  +4,8  @@@        appschema  2014-­‐01-­‐07T23:47:31Z  David  E.  Wheeler  <d    users  [appschema]  2014-­‐01-­‐08T04:13:38Z  David  E.  Wh ++<<<<<<<  HEAD  +flips  [appschema  users]  2014-­‐01-­‐08T04:48:29Z  David ++======= +  insert_user  [users  appschema]  2014-­‐01-­‐08T04:52:50Z ++>>>>>>>  Add  `insert_user()`. Wha Happen? >
  704. >  git  diff diff  -­‐-­‐cc  sqitch.plan index  7526d1c,e2c966c..0000000 -­‐-­‐-­‐  a/sqitch.plan

    +++  b/sqitch.plan @@@  -­‐4,4  -­‐4,4  +4,8  @@@        appschema  2014-­‐01-­‐07T23:47:31Z  David  E.  Wheeler  <d    users  [appschema]  2014-­‐01-­‐08T04:13:38Z  David  E.  Wh ++<<<<<<<  HEAD  +flips  [appschema  users]  2014-­‐01-­‐08T04:48:29Z  David ++======= +  insert_user  [users  appschema]  2014-­‐01-­‐08T04:52:50Z ++>>>>>>>  Add  `insert_user()`. Wha Happen? >
  705. >  git  diff diff  -­‐-­‐cc  sqitch.plan index  7526d1c,e2c966c..0000000 -­‐-­‐-­‐  a/sqitch.plan

    +++  b/sqitch.plan @@@  -­‐4,4  -­‐4,4  +4,8  @@@        appschema  2014-­‐01-­‐07T23:47:31Z  David  E.  Wheeler  <d    users  [appschema]  2014-­‐01-­‐08T04:13:38Z  David  E.  Wh ++<<<<<<<  HEAD  +flips  [appschema  users]  2014-­‐01-­‐08T04:48:29Z  David ++======= +  insert_user  [users  appschema]  2014-­‐01-­‐08T04:52:50Z ++>>>>>>>  Add  `insert_user()`. Wha Happen? > B
  706. >  git  diff diff  -­‐-­‐cc  sqitch.plan index  7526d1c,e2c966c..0000000 -­‐-­‐-­‐  a/sqitch.plan

    +++  b/sqitch.plan @@@  -­‐4,4  -­‐4,4  +4,8  @@@        appschema  2014-­‐01-­‐07T23:47:31Z  David  E.  Wheeler  <d    users  [appschema]  2014-­‐01-­‐08T04:13:38Z  David  E.  Wh ++<<<<<<<  HEAD  +flips  [appschema  users]  2014-­‐01-­‐08T04:48:29Z  David ++======= +  insert_user  [users  appschema]  2014-­‐01-­‐08T04:52:50Z ++>>>>>>>  Add  `insert_user()`. Wha Happen? > C B
  707. >  git  diff diff  -­‐-­‐cc  sqitch.plan index  7526d1c,e2c966c..0000000 -­‐-­‐-­‐  a/sqitch.plan

    +++  b/sqitch.plan @@@  -­‐4,4  -­‐4,4  +4,8  @@@        appschema  2014-­‐01-­‐07T23:47:31Z  David  E.  Wheeler  <d    users  [appschema]  2014-­‐01-­‐08T04:13:38Z  David  E.  Wh ++<<<<<<<  HEAD  +flips  [appschema  users]  2014-­‐01-­‐08T04:48:29Z  David ++======= +  insert_user  [users  appschema]  2014-­‐01-­‐08T04:52:50Z ++>>>>>>>  Add  `insert_user()`. Wha Happen? > C D B
  708. Scratch that Sqitch antisocial network

  709. Scratch that Sqitch Screwed either way? antisocial network

  710. Scratch that Sqitch Screwed either way? Fortunately, this is Git

    antisocial network
  711. Scratch that Sqitch Screwed either way? Fortunately, this is Git

    Tell it to treat Sqitch plans differently antisocial network
  712. Scratch that Sqitch Screwed either way? Fortunately, this is Git

    Tell it to treat Sqitch plans differently Changes on single lines antisocial network
  713. Scratch that Sqitch Screwed either way? Fortunately, this is Git

    Tell it to treat Sqitch plans differently Changes on single lines Only appended to plan file antisocial network
  714. Scratch that Sqitch Screwed either way? Fortunately, this is Git

    Tell it to treat Sqitch plans differently Changes on single lines Only appended to plan file Use the “union” merge antisocial network
  715. Re: Union Merge

  716. Re: Union Merge Run 3-way file level merge for text

    files, but take lines from both versions, instead of leaving conflict markers. This tends to leave the added lines in the resulting file in random order and the user should verify the result. Do not use this if you do not understand the implications. —Git Manual
  717. Hallelunion antisocial network

  718. Hallelunion Just appends lines antisocial network

  719. Hallelunion Just appends lines Exactly how changes work antisocial network

  720. Hallelunion Just appends lines Exactly how changes work Let’s clean

    up our mess antisocial network
  721. Hallelunion Just appends lines Exactly how changes work Let’s clean

    up our mess And try again antisocial network
  722. Reemerge >

  723.    git  rebase  -­‐-­‐abort > Reemerge >

  724.    echo  sqitch.plan  merge=union  >  .gitattributes >    git  rebase

     -­‐-­‐abort > Reemerge >
  725.    echo  sqitch.plan  merge=union  >  .gitattributes >    git  rebase

     master First,  rewinding  head  to  replay  your  work  on  top  of  it... Applying:  Add  `insert_user()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan Applying:  Add  `change_pass()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan >    git  rebase  -­‐-­‐abort > Reemerge >
  726.    echo  sqitch.plan  merge=union  >  .gitattributes >    git  rebase

     master First,  rewinding  head  to  replay  your  work  on  top  of  it... Applying:  Add  `insert_user()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan Applying:  Add  `change_pass()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan >    git  rebase  -­‐-­‐abort > Reemerge > Back to B, applies C
  727.    echo  sqitch.plan  merge=union  >  .gitattributes >    git  rebase

     master First,  rewinding  head  to  replay  your  work  on  top  of  it... Applying:  Add  `insert_user()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan Applying:  Add  `change_pass()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan >    git  rebase  -­‐-­‐abort > Reemerge > That’s D
  728.    echo  sqitch.plan  merge=union  >  .gitattributes >    git  rebase

     master First,  rewinding  head  to  replay  your  work  on  top  of  it... Applying:  Add  `insert_user()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan Applying:  Add  `change_pass()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan >    git  rebase  -­‐-­‐abort > Reemerge > Union merge
  729.    echo  sqitch.plan  merge=union  >  .gitattributes >    git  rebase

     master First,  rewinding  head  to  replay  your  work  on  top  of  it... Applying:  Add  `insert_user()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan Applying:  Add  `change_pass()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan >    git  rebase  -­‐-­‐abort > Reemerge > That’s E
  730.    echo  sqitch.plan  merge=union  >  .gitattributes >    git  rebase

     master First,  rewinding  head  to  replay  your  work  on  top  of  it... Applying:  Add  `insert_user()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan Applying:  Add  `change_pass()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan >    git  rebase  -­‐-­‐abort > Reemerge > Union merge
  731.    echo  sqitch.plan  merge=union  >  .gitattributes >    git  rebase

     master First,  rewinding  head  to  replay  your  work  on  top  of  it... Applying:  Add  `insert_user()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan Applying:  Add  `change_pass()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan >    git  rebase  -­‐-­‐abort > Reemerge > Success!
  732.    echo  sqitch.plan  merge=union  >  .gitattributes >    git  rebase

     master First,  rewinding  head  to  replay  your  work  on  top  of  it... Applying:  Add  `insert_user()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan Applying:  Add  `change_pass()`. Using  index  info  to  reconstruct  a  base  tree... M   sqitch.plan Falling  back  to  patching  base  and  3-­‐way  merge... Auto-­‐merging  sqitch.plan >    git  rebase  -­‐-­‐abort > Reemerge >    emacs  sqitch.plan > Success!
  733. sqitch.plan What’s the Plan, Man? %syntax-­‐version=1.0.0-­‐b2   %project=flipr   %uri=https://github.com/theory/agile-­‐flipr

      ! appschema  2014-­‐01-­‐07T23:47:31Z  David  E.  Wheeler   <david@justatheory.com>  #  Adds  flipr  app  schema.   users  [appschema]  2014-­‐01-­‐08T04:13:38Z  David  E.  Wheeler   <david@justatheory.com>  #  Creates  table  to  track  our   users.   flips  [appschema  users]  2014-­‐01-­‐08T04:48:29Z  David  E.   Wheeler  <david@justatheory.com>  #  Adds  table  for  storing   flips.   insert_user  [users  appschema]  2014-­‐01-­‐08T04:52:50Z  David   E.  Wheeler  <david@justatheory.com>  #  Creates  a  function  to   insert  a  user.   change_pass  [users  appschema]  2014-­‐01-­‐08T05:23:28Z  David   E.  Wheeler  <david@justatheory.com>  #  Creates  a  function  to
  734. sqitch.plan What’s the Plan, Man? %syntax-­‐version=1.0.0-­‐b2   %project=flipr   %uri=https://github.com/theory/agile-­‐flipr

      ! appschema  2014-­‐01-­‐07T23:47:31Z  David  E.  Wheeler   <david@justatheory.com>  #  Adds  flipr  app  schema.   users  [appschema]  2014-­‐01-­‐08T04:13:38Z  David  E.  Wheeler   <david@justatheory.com>  #  Creates  table  to  track  our   users.   flips  [appschema  users]  2014-­‐01-­‐08T04:48:29Z  David  E.   Wheeler  <david@justatheory.com>  #  Adds  table  for  storing   flips.   insert_user  [users  appschema]  2014-­‐01-­‐08T04:52:50Z  David   E.  Wheeler  <david@justatheory.com>  #  Creates  a  function  to   insert  a  user.   change_pass  [users  appschema]  2014-­‐01-­‐08T05:23:28Z  David   E.  Wheeler  <david@justatheory.com>  #  Creates  a  function  to
  735. sqitch.plan What’s the Plan, Man? %syntax-­‐version=1.0.0-­‐b2   %project=flipr   %uri=https://github.com/theory/agile-­‐flipr

      ! appschema  2014-­‐01-­‐07T23:47:31Z  David  E.  Wheeler   <david@justatheory.com>  #  Adds  flipr  app  schema.   users  [appschema]  2014-­‐01-­‐08T04:13:38Z  David  E.  Wheeler   <david@justatheory.com>  #  Creates  table  to  track  our   users.   flips  [appschema  users]  2014-­‐01-­‐08T04:48:29Z  David  E.   Wheeler  <david@justatheory.com>  #  Adds  table  for  storing   flips.   insert_user  [users  appschema]  2014-­‐01-­‐08T04:52:50Z  David   E.  Wheeler  <david@justatheory.com>  #  Creates  a  function  to   insert  a  user.   change_pass  [users  appschema]  2014-­‐01-­‐08T05:23:28Z  David   E.  Wheeler  <david@justatheory.com>  #  Creates  a  function  to
  736. sqitch.plan What’s the Plan, Man? %syntax-­‐version=1.0.0-­‐b2   %project=flipr   %uri=https://github.com/theory/agile-­‐flipr

      ! appschema  2014-­‐01-­‐07T23:47:31Z  David  E.  Wheeler   <david@justatheory.com>  #  Adds  flipr  app  schema.   users  [appschema]  2014-­‐01-­‐08T04:13:38Z  David  E.  Wheeler   <david@justatheory.com>  #  Creates  table  to  track  our   users.   flips  [appschema  users]  2014-­‐01-­‐08T04:48:29Z  David  E.   Wheeler  <david@justatheory.com>  #  Adds  table  for  storing   flips.   insert_user  [users  appschema]  2014-­‐01-­‐08T04:52:50Z  David   E.  Wheeler  <david@justatheory.com>  #  Creates  a  function  to   insert  a  user.   change_pass  [users  appschema]  2014-­‐01-­‐08T05:23:28Z  David   E.  Wheeler  <david@justatheory.com>  #  Creates  a  function  to
  737. sqitch.plan What’s the Plan, Man? %syntax-­‐version=1.0.0-­‐b2   %project=flipr   %uri=https://github.com/theory/agile-­‐flipr

      ! appschema  2014-­‐01-­‐07T23:47:31Z  David  E.  Wheeler   <david@justatheory.com>  #  Adds  flipr  app  schema.   users  [appschema]  2014-­‐01-­‐08T04:13:38Z  David  E.  Wheeler   <david@justatheory.com>  #  Creates  table  to  track  our   users.   flips  [appschema  users]  2014-­‐01-­‐08T04:48:29Z  David  E.   Wheeler  <david@justatheory.com>  #  Adds  table  for  storing   flips.   insert_user  [users  appschema]  2014-­‐01-­‐08T04:52:50Z  David   E.  Wheeler  <david@justatheory.com>  #  Creates  a  function  to   insert  a  user.   change_pass  [users  appschema]  2014-­‐01-­‐08T05:23:28Z  David   E.  Wheeler  <david@justatheory.com>  #  Creates  a  function  to
  738. sqitch.plan What’s the Plan, Man? %syntax-­‐version=1.0.0-­‐b2   %project=flipr   %uri=https://github.com/theory/agile-­‐flipr

      ! appschema  2014-­‐01-­‐07T23:47:31Z  David  E.  Wheeler   <david@justatheory.com>  #  Adds  flipr  app  schema.   users  [appschema]  2014-­‐01-­‐08T04:13:38Z  David  E.  Wheeler   <david@justatheory.com>  #  Creates  table  to  track  our   users.   flips  [appschema  users]  2014-­‐01-­‐08T04:48:29Z  David  E.   Wheeler  <david@justatheory.com>  #  Adds  table  for  storing   flips.   insert_user  [users  appschema]  2014-­‐01-­‐08T04:52:50Z  David   E.  Wheeler  <david@justatheory.com>  #  Creates  a  function  to   insert  a  user.   change_pass  [users  appschema]  2014-­‐01-­‐08T05:23:28Z  David   E.  Wheeler  <david@justatheory.com>  #  Creates  a  function  to
  739. sqitch.plan What’s the Plan, Man? %syntax-­‐version=1.0.0-­‐b2   %project=flipr   %uri=https://github.com/theory/agile-­‐flipr

      ! appschema  2014-­‐01-­‐07T23:47:31Z  David  E.  Wheeler   <david@justatheory.com>  #  Adds  flipr  app  schema.   users  [appschema]  2014-­‐01-­‐08T04:13:38Z  David  E.  Wheeler   <david@justatheory.com>  #  Creates  table  to  track  our   users.   flips  [appschema  users]  2014-­‐01-­‐08T04:48:29Z  David  E.   Wheeler  <david@justatheory.com>  #  Adds  table  for  storing   flips.   insert_user  [users  appschema]  2014-­‐01-­‐08T04:52:50Z  David   E.  Wheeler  <david@justatheory.com>  #  Creates  a  function  to   insert  a  user.   change_pass  [users  appschema]  2014-­‐01-­‐08T05:23:28Z  David   E.  Wheeler  <david@justatheory.com>  #  Creates  a  function  to Perfect
  740. Work It >

  741. >  sqitch  rebase  -­‐y Reverting  all  changes  from  flipr_test  

     -­‐  change_pass  ..  ok    -­‐  insert_user  ..  ok    -­‐  users  ........  ok    -­‐  appschema  ....  ok Deploying  changes  to  flipr_test    +  appschema  ....  ok    +  users  ........  ok    +  flips  ........  ok    +  insert_user  ..  ok    +  change_pass  ..  ok > Work It >
  742. >  sqitch  rebase  -­‐y Reverting  all  changes  from  flipr_test  

     -­‐  change_pass  ..  ok    -­‐  insert_user  ..  ok    -­‐  users  ........  ok    -­‐  appschema  ....  ok Deploying  changes  to  flipr_test    +  appschema  ....  ok    +  users  ........  ok    +  flips  ........  ok    +  insert_user  ..  ok    +  change_pass  ..  ok > Work It > {
  743. >  sqitch  rebase  -­‐y Reverting  all  changes  from  flipr_test  

     -­‐  change_pass  ..  ok    -­‐  insert_user  ..  ok    -­‐  users  ........  ok    -­‐  appschema  ....  ok Deploying  changes  to  flipr_test    +  appschema  ....  ok    +  users  ........  ok    +  flips  ........  ok    +  insert_user  ..  ok    +  change_pass  ..  ok > Work It > { {
  744. >  sqitch  rebase  -­‐y Reverting  all  changes  from  flipr_test  

     -­‐  change_pass  ..  ok    -­‐  insert_user  ..  ok    -­‐  users  ........  ok    -­‐  appschema  ....  ok Deploying  changes  to  flipr_test    +  appschema  ....  ok    +  users  ........  ok    +  flips  ........  ok    +  insert_user  ..  ok    +  change_pass  ..  ok > Work It > { { Awesomsauce
  745. Make it So >

  746. >  git  add  . > Make it So >

  747. >  git  add  . >    git  commit  -­‐m  'Use

     union  merge  for  `sqitch.plan`.' [userfuncs  f38ef5c]  Use  union  merge  for  `sqitch.plan`.  1  file  changed,  1  insertion(+)  create  mode  100644  .gitattributes > Make it So >
  748. >  git  add  . >    git  commit  -­‐m  'Use

     union  merge  for  `sqitch.plan`.' [userfuncs  f38ef5c]  Use  union  merge  for  `sqitch.plan`.  1  file  changed,  1  insertion(+)  create  mode  100644  .gitattributes >    git  push  -­‐-­‐force  origin  userfuncs Counting  objects:  31,  done. Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (24/24),  done. Writing  objects:  100%  (25/25),  3.83  KiB,  done. Total  25  (delta  7),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git  +  1813323...f38ef5c  userfuncs  -­‐>  userfuncs  (forced  upda > Make it So > Overwrite history
  749. >  git  add  . >    git  commit  -­‐m  'Use

     union  merge  for  `sqitch.plan`.' [userfuncs  f38ef5c]  Use  union  merge  for  `sqitch.plan`.  1  file  changed,  1  insertion(+)  create  mode  100644  .gitattributes >    git  push  -­‐-­‐force  origin  userfuncs Counting  objects:  31,  done. Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (24/24),  done. Writing  objects:  100%  (25/25),  3.83  KiB,  done. Total  25  (delta  7),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git  +  1813323...f38ef5c  userfuncs  -­‐>  userfuncs  (forced  upda > Make it So >
  750. >

  751. >  git  checkout  master Switched  to  branch  'master' > >

  752.    git  merge  -­‐-­‐no-­‐ff  userfuncs  -­‐m  'Merge  branch  "userfuncs".'  

                Merge  made  by  the  'recursive'  strategy.  .gitattributes                  |    1  +  deploy/change_pass.sql  |  21  ++++++++++++++++++  deploy/insert_user.sql  |  14  ++++++++++++  revert/change_pass.sql  |    7  ++++++  revert/insert_user.sql  |    7  ++++++  sqitch.plan                        |    2  ++  test/change_pass.sql      |  52  ++++++++++++++++++++++++++++++++++  test/insert_user.sql      |  69  ++++++++++++++++++++++++++++++++++  verify/change_pass.sql  |    7  ++++++  verify/insert_user.sql  |  10  +++++++++  10  files  changed,  190  insertions(+)  create  mode  100644  .gitattributes  create  mode  100644  deploy/change_pass.sql  create  mode  100644  deploy/insert_user.sql  create  mode  100644  revert/change_pass.sql  create  mode  100644  revert/insert_user.sql  create  mode  100644  test/change_pass.sql  create  mode  100644  test/insert_user.sql  create  mode  100644  verify/change_pass.sql  create  mode  100644  verify/insert_user.sql > >  git  checkout  master Switched  to  branch  'master' > >
  753.    git  merge  -­‐-­‐no-­‐ff  userfuncs  -­‐m  'Merge  branch  "userfuncs".'  

                Merge  made  by  the  'recursive'  strategy.  .gitattributes                  |    1  +  deploy/change_pass.sql  |  21  ++++++++++++++++++  deploy/insert_user.sql  |  14  ++++++++++++  revert/change_pass.sql  |    7  ++++++  revert/insert_user.sql  |    7  ++++++  sqitch.plan                        |    2  ++  test/change_pass.sql      |  52  ++++++++++++++++++++++++++++++++++  test/insert_user.sql      |  69  ++++++++++++++++++++++++++++++++++  verify/change_pass.sql  |    7  ++++++  verify/insert_user.sql  |  10  +++++++++  10  files  changed,  190  insertions(+)  create  mode  100644  .gitattributes  create  mode  100644  deploy/change_pass.sql  create  mode  100644  deploy/insert_user.sql  create  mode  100644  revert/change_pass.sql  create  mode  100644  revert/insert_user.sql  create  mode  100644  test/change_pass.sql  create  mode  100644  test/insert_user.sql  create  mode  100644  verify/change_pass.sql  create  mode  100644  verify/insert_user.sql > >  git  checkout  master Switched  to  branch  'master' > > \O/
  754. Pusher >

  755.    git  push Counting  objects:  1,  done. Writing  objects:  100%

     (1/1),  231  bytes,  done. Total  1  (delta  0),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git      e1cfc5d..7c5937a    master  -­‐>  master > Pusher >
  756. antisocial network

  757. Ship it! antisocial network

  758. Ship Shape antisocial network

  759. Ship Shape Good work so far antisocial network

  760. Ship Shape Good work so far People gonna flip out

    antisocial network
  761. Ship Shape Good work so far People gonna flip out

    Let’s tag a dev release antisocial network
  762. Ship Shape Good work so far People gonna flip out

    Let’s tag a dev release Bundle it up antisocial network
  763. Ship Shape Good work so far People gonna flip out

    Let’s tag a dev release Bundle it up And ship it antisocial network
  764. You’re It >

  765.    sqitch  tag  v1.0.0-­‐r1  -­‐n  'Tag  v1.0.0-­‐r1.' Tagged  "change_pass"  with

     @v1.0.0-­‐r1 > You’re It >
  766.    git  commit  -­‐am  'Tag  the  database  @v1.0.0-­‐r1.' [master  dce7606]

     Tag  the  database  @v1.0.0-­‐r1.  1  file  changed,  1  insertion(+) >    sqitch  tag  v1.0.0-­‐r1  -­‐n  'Tag  v1.0.0-­‐r1.' Tagged  "change_pass"  with  @v1.0.0-­‐r1 > You’re It >
  767.    git  tag  v1.0.0-­‐r1  -­‐am  'Tag  v1.0.0-­‐r1.' >    git

     commit  -­‐am  'Tag  the  database  @v1.0.0-­‐r1.' [master  dce7606]  Tag  the  database  @v1.0.0-­‐r1.  1  file  changed,  1  insertion(+) >    sqitch  tag  v1.0.0-­‐r1  -­‐n  'Tag  v1.0.0-­‐r1.' Tagged  "change_pass"  with  @v1.0.0-­‐r1 > You’re It > In sync. In sync.
  768.    git  tag  v1.0.0-­‐r1  -­‐am  'Tag  v1.0.0-­‐r1.' >    git

     commit  -­‐am  'Tag  the  database  @v1.0.0-­‐r1.' [master  dce7606]  Tag  the  database  @v1.0.0-­‐r1.  1  file  changed,  1  insertion(+) >    sqitch  tag  v1.0.0-­‐r1  -­‐n  'Tag  v1.0.0-­‐r1.' Tagged  "change_pass"  with  @v1.0.0-­‐r1 >    git  push Counting  objects:  5,  done. Writing  objects:  100%  (3/3),  344  bytes,  done. Total  3  (delta  2),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git      7c5937a..dce7606    master  -­‐>  master > You’re It >
  769.    git  tag  v1.0.0-­‐r1  -­‐am  'Tag  v1.0.0-­‐r1.' >    git

     commit  -­‐am  'Tag  the  database  @v1.0.0-­‐r1.' [master  dce7606]  Tag  the  database  @v1.0.0-­‐r1.  1  file  changed,  1  insertion(+) >    sqitch  tag  v1.0.0-­‐r1  -­‐n  'Tag  v1.0.0-­‐r1.' Tagged  "change_pass"  with  @v1.0.0-­‐r1 >    git  push Counting  objects:  5,  done. Writing  objects:  100%  (3/3),  344  bytes,  done. Total  3  (delta  2),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git      7c5937a..dce7606    master  -­‐>  master >    git  push  -­‐-­‐tags To  https://github.com/theory/agile-­‐flipr.git  *  [new  tag]                  v1.0.0-­‐r1  -­‐>  v1.0.0-­‐r1 > You’re It >
  770. Bundle Up >

  771.    sqitch  bundle  -­‐-­‐dest-­‐dir  flipr-­‐1.0.0-­‐r1 Bundling  into  flipr-­‐1.0.0-­‐r1 Writing  config

    Writing  plan Writing  scripts    +  appschema    +  users    +  flips    +  insert_user    +  change_pass  @v1.0.0-­‐r1 > Bundle Up >
  772.    sqitch  bundle  -­‐-­‐dest-­‐dir  flipr-­‐1.0.0-­‐r1 Bundling  into  flipr-­‐1.0.0-­‐r1 Writing  config

    Writing  plan Writing  scripts    +  appschema    +  users    +  flips    +  insert_user    +  change_pass  @v1.0.0-­‐r1 > Bundle Up > {
  773. Bundled? >

  774. >  cd  flipr-­‐1.0.0-­‐r1 > Bundled? >

  775.    createdb  flipr_qa   > >  cd  flipr-­‐1.0.0-­‐r1 > Bundled?

    >
  776.    createdb  flipr_qa   > >  cd  flipr-­‐1.0.0-­‐r1 > Bundled?

    >    sqitch  deploy  db:pg:flipr_qa Adding  registry  tables  to  db:pg:flipr_qa Deploying  changes  to  db:pg:flipr_qa    +  appschema  ...............  ok    +  users  ...................  ok    +  flips  ...................  ok    +  insert_user  .............  ok    +  change_pass  @v1.0.0-­‐r1  ..  ok >
  777.    createdb  flipr_qa   > >  cd  flipr-­‐1.0.0-­‐r1 > Bundled?

    > Ship it!    sqitch  deploy  db:pg:flipr_qa Adding  registry  tables  to  db:pg:flipr_qa Deploying  changes  to  db:pg:flipr_qa    +  appschema  ...............  ok    +  users  ...................  ok    +  flips  ...................  ok    +  insert_user  .............  ok    +  change_pass  @v1.0.0-­‐r1  ..  ok >
  778. antisocial network Merge Madness

  779. antisocial network Merge Madness Merge everything

  780. antisocial network Merge Madness Merge everything Back to master

  781. antisocial network Merge Madness Merge everything Back to master users

  782. antisocial network Merge Madness Merge everything Back to master users

    flips
  783. antisocial network Merge Madness Merge everything Back to master users

    flips userfuncs
  784. antisocial network Merge Madness Merge everything Back to master users

    flips userfuncs Union merge sqitch.plan
  785. antisocial network Merge Madness Merge everything Back to master users

    flips userfuncs Union merge sqitch.plan Bundle and ship
  786. antisocial network Merge Madness Merge everything Back to master users

    flips userfuncs Union merge sqitch.plan Bundle and ship https:/ /github.com/ theory/agile-flipr.git
  787. Ruh-Roh >

  788. Ruh-Roh > >  git  reset  -­‐-­‐hard  reltag HEAD  is  now

     at  dce7606  Tag  the  database  @v1.0.0-­‐r1. >
  789.    psql  -­‐d  flipr_test  -­‐c  "        SELECT

     flipr.insert_user('foo',  'secr3t'),                      flipr.insert_user('bar',  'secr3t');        SELECT  nickname,  password  FROM  flipr.users; "  nickname  |                          password                           -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐  foo            |  9695da4dd567a19f9b92065f240c6725  bar            |  9695da4dd567a19f9b92065f240c6725 (2  rows) > Ruh-Roh > >  git  reset  -­‐-­‐hard  reltag HEAD  is  now  at  dce7606  Tag  the  database  @v1.0.0-­‐r1. > Same password
  790.    psql  -­‐d  flipr_test  -­‐c  "        SELECT

     flipr.insert_user('foo',  'secr3t'),                      flipr.insert_user('bar',  'secr3t');        SELECT  nickname,  password  FROM  flipr.users; "  nickname  |                          password                           -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐  foo            |  9695da4dd567a19f9b92065f240c6725  bar            |  9695da4dd567a19f9b92065f240c6725 (2  rows) > Ruh-Roh > >  git  reset  -­‐-­‐hard  reltag HEAD  is  now  at  dce7606  Tag  the  database  @v1.0.0-­‐r1. >
  791.    psql  -­‐d  flipr_test  -­‐c  "        SELECT

     flipr.insert_user('foo',  'secr3t'),                      flipr.insert_user('bar',  'secr3t');        SELECT  nickname,  password  FROM  flipr.users; "  nickname  |                          password                           -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐  foo            |  9695da4dd567a19f9b92065f240c6725  bar            |  9695da4dd567a19f9b92065f240c6725 (2  rows) > Ruh-Roh > Not good. >  git  reset  -­‐-­‐hard  reltag HEAD  is  now  at  dce7606  Tag  the  database  @v1.0.0-­‐r1. >
  792. PGCryptonite >

  793.    sqitch  add  pgcrypto  -­‐n  'Loads  pgcrypto  extension.' Adding  deploy/pgcrypto.sql

    Adding  revert/pgcrypto.sql Adding  test/pgcrypto.sql Adding  verify/pgcrypto.sql Added  "pgcrypto"  to  sqitch.plan > PGCryptonite >
  794.    sqitch  add  pgcrypto  -­‐n  'Loads  pgcrypto  extension.' Adding  deploy/pgcrypto.sql

    Adding  revert/pgcrypto.sql Adding  test/pgcrypto.sql Adding  verify/pgcrypto.sql Added  "pgcrypto"  to  sqitch.plan > PGCryptonite >    emacs  deploy/pgcrpyto.sql >
  795. deploy/pgcrypto deploy/pgcrypto.sql -­‐-­‐  Deploy  pgcrypto   ! BEGIN;   !

    ! ! COMMIT; -­‐-­‐  XXX  Add  DDLs  here.
  796. deploy/pgcrypto deploy/pgcrypto.sql -­‐-­‐  Deploy  pgcrypto   ! BEGIN;   !

    ! ! COMMIT; CREATE  EXTENSION  pgcrypto;
  797.    sqitch  add  pgcrypto  -­‐n  'Loads  pgcrypto  extension.'   Adding

     deploy/pgcrypto.sql   Adding  revert/pgcrypto.sql   Adding  test/pgcrypto.sql   Adding  verify/pgcrypto.sql   Added  "pgcrypto"  to  sqitch.plan   >  emacs  deploy/pgcrpyto.sql   > PGCryptonite >
  798.    sqitch  add  pgcrypto  -­‐n  'Loads  pgcrypto  extension.'   Adding

     deploy/pgcrypto.sql   Adding  revert/pgcrypto.sql   Adding  test/pgcrypto.sql   Adding  verify/pgcrypto.sql   Added  "pgcrypto"  to  sqitch.plan   >  emacs  deploy/pgcrpyto.sql   > PGCryptonite >    emacs  verify/pgcrpyto.sql >
  799. -­‐-­‐  Verify  pgcrypto   ! BEGIN; verify/pgcrypto verify/pgcrypto.sql -­‐-­‐  XXX

     Add  verifications  here. COMMIT;
  800. -­‐-­‐  Verify  pgcrypto   ! BEGIN; verify/pgcrypto verify/pgcrypto.sql COMMIT; SELECT

     1/count(*)  FROM  pg_extension  WHERE  extname  =  'pgcrypto'; SELECT  has_function_privilege('crypt(text,  text)',  'execute'); SELECT  has_function_privilege('gen_salt(text)',  'execute');
  801. -­‐-­‐  Verify  pgcrypto   ! BEGIN; verify/pgcrypto verify/pgcrypto.sql COMMIT; SELECT

     1/count(*)  FROM  pg_extension  WHERE  extname  =  'pgcrypto'; SELECT  has_function_privilege('crypt(text,  text)',  'execute'); SELECT  has_function_privilege('gen_salt(text)',  'execute');
  802. -­‐-­‐  Verify  pgcrypto   ! BEGIN; verify/pgcrypto verify/pgcrypto.sql COMMIT; SELECT

     1/count(*)  FROM  pg_extension  WHERE  extname  =  'pgcrypto'; SELECT  has_function_privilege('crypt(text,  text)',  'execute'); SELECT  has_function_privilege('gen_salt(text)',  'execute');
  803. You Know the Drill antisocial network

  804. You Know the Drill Write revert script antisocial network

  805. You Know the Drill Write revert script Add test antisocial

    network
  806. You Know the Drill Write revert script Add test Use

    has_function() antisocial network
  807. You Know the Drill Write revert script Add test Use

    has_function() Commit antisocial network
  808. You Know the Drill Write revert script Add test Use

    has_function() Commit Push antisocial network
  809. You Know the Drill Write revert script Add test Use

    has_function() Commit Push Modify the insert_user test antisocial network
  810. >

  811. >    git  diff  test/insert_user.sql diff  -­‐-­‐git  a/test/insert_user.sql  b/test/insert_user.sql index

     225bb18..2a775a6  100644 -­‐-­‐-­‐  a/test/insert_user.sql +++  b/test/insert_user.sql @@  -­‐29,25  +29,25  @@  SELECT  lives_ok(          'Insert  a  user'  );   -­‐SELECT  row_eq( -­‐      'SELECT  *  FROM  users', -­‐      ROW('theory',  md5('foo'),  NOW())::users, -­‐      'The  user  should  have  been  inserted' -­‐); +SELECT  ok(  EXISTS( +        SELECT  1  FROM  flipr.users +          WHERE  nickname  =  'theory' +              AND  password  =  crypt('foo',  password) +),  'The  user  should  have  been  inserted'  );    SELECT  lives_ok(          $$  SELECT  insert_user('strongrrl',  'w00t')  $$,          'Insert  another  user'  );
  812. >    git  diff  test/insert_user.sql diff  -­‐-­‐git  a/test/insert_user.sql  b/test/insert_user.sql index

     225bb18..2a775a6  100644 -­‐-­‐-­‐  a/test/insert_user.sql +++  b/test/insert_user.sql @@  -­‐29,25  +29,25  @@  SELECT  lives_ok(          'Insert  a  user'  );   -­‐SELECT  row_eq( -­‐      'SELECT  *  FROM  users', -­‐      ROW('theory',  md5('foo'),  NOW())::users, -­‐      'The  user  should  have  been  inserted' -­‐); +SELECT  ok(  EXISTS( +        SELECT  1  FROM  flipr.users +          WHERE  nickname  =  'theory' +              AND  password  =  crypt('foo',  password) +),  'The  user  should  have  been  inserted'  );    SELECT  lives_ok(          $$  SELECT  insert_user('strongrrl',  'w00t')  $$,          'Insert  another  user'  );
  813. >    git  diff  test/insert_user.sql diff  -­‐-­‐git  a/test/insert_user.sql  b/test/insert_user.sql index

     225bb18..2a775a6  100644 -­‐-­‐-­‐  a/test/insert_user.sql +++  b/test/insert_user.sql @@  -­‐29,25  +29,25  @@  SELECT  lives_ok(          'Insert  a  user'  );   -­‐SELECT  row_eq( -­‐      'SELECT  *  FROM  users', -­‐      ROW('theory',  md5('foo'),  NOW())::users, -­‐      'The  user  should  have  been  inserted' -­‐); +SELECT  ok(  EXISTS( +        SELECT  1  FROM  flipr.users +          WHERE  nickname  =  'theory' +              AND  password  =  crypt('foo',  password) +),  'The  user  should  have  been  inserted'  );    SELECT  lives_ok(          $$  SELECT  insert_user('strongrrl',  'w00t')  $$,          'Insert  another  user'  );
  814. -­‐SELECT  bag_eq(   -­‐        'SELECT  *  FROM

     users',   -­‐        $$  VALUES   -­‐                ('theory',        md5('foo'),    NOW()),   -­‐                ('strongrrl',  md5('w00t'),  NOW())   -­‐        $$,   -­‐        'Both  users  should  be  present'   -­‐);   +SELECT  is(COUNT(*)::INT,  2,  'There  should  be  two  users')   +    FROM  flipr.users;   +   +SELECT  ok(  EXISTS(   +        SELECT  1  FROM  flipr.users   +          WHERE  nickname  =  'strongrrl'   +              AND  password  =  crypt('w00t',  password)   +),  'The  second  user  should  have  been  inserted'  );        SELECT  throws_ok(            $$  SELECT  insert_user('theory',  'ha-­‐ha')  $$,  
  815. -­‐SELECT  bag_eq(   -­‐        'SELECT  *  FROM

     users',   -­‐        $$  VALUES   -­‐                ('theory',        md5('foo'),    NOW()),   -­‐                ('strongrrl',  md5('w00t'),  NOW())   -­‐        $$,   -­‐        'Both  users  should  be  present'   -­‐);   +SELECT  is(COUNT(*)::INT,  2,  'There  should  be  two  users')   +    FROM  flipr.users;   +   +SELECT  ok(  EXISTS(   +        SELECT  1  FROM  flipr.users   +          WHERE  nickname  =  'strongrrl'   +              AND  password  =  crypt('w00t',  password)   +),  'The  second  user  should  have  been  inserted'  );        SELECT  throws_ok(            $$  SELECT  insert_user('theory',  'ha-­‐ha')  $$,  
  816. -­‐SELECT  bag_eq(   -­‐        'SELECT  *  FROM

     users',   -­‐        $$  VALUES   -­‐                ('theory',        md5('foo'),    NOW()),   -­‐                ('strongrrl',  md5('w00t'),  NOW())   -­‐        $$,   -­‐        'Both  users  should  be  present'   -­‐);   +SELECT  is(COUNT(*)::INT,  2,  'There  should  be  two  users')   +    FROM  flipr.users;   +   +SELECT  ok(  EXISTS(   +        SELECT  1  FROM  flipr.users   +          WHERE  nickname  =  'strongrrl'   +              AND  password  =  crypt('w00t',  password)   +),  'The  second  user  should  have  been  inserted'  );        SELECT  throws_ok(            $$  SELECT  insert_user('theory',  'ha-­‐ha')  $$,  
  817. -­‐SELECT  bag_eq(   -­‐        'SELECT  *  FROM

     users',   -­‐        $$  VALUES   -­‐                ('theory',        md5('foo'),    NOW()),   -­‐                ('strongrrl',  md5('w00t'),  NOW())   -­‐        $$,   -­‐        'Both  users  should  be  present'   -­‐);   +SELECT  is(COUNT(*)::INT,  2,  'There  should  be  two  users')   +    FROM  flipr.users;   +   +SELECT  ok(  EXISTS(   +        SELECT  1  FROM  flipr.users   +          WHERE  nickname  =  'strongrrl'   +              AND  password  =  crypt('w00t',  password)   +),  'The  second  user  should  have  been  inserted'  );        SELECT  throws_ok(            $$  SELECT  insert_user('theory',  'ha-­‐ha')  $$,  
  818. @@  -­‐56,14  +56,8  @@  SELECT  throws_ok(        

       'Should  get  an  error  for  duplicate  nickname'    );       -­‐SELECT  bag_eq(   -­‐        'SELECT  *  FROM  users',   -­‐        $$  VALUES   -­‐                ('theory',        md5('foo'),    NOW()),   -­‐                ('strongrrl',  md5('w00t'),  NOW())   -­‐        $$,   -­‐        'Should  still  have  just  the  two  users'   -­‐);   +SELECT  is(COUNT(*)::INT,  2,  'Should  still  have  two  users')   +    FROM  flipr.users;        SELECT  finish();    ROLLBACK;   >
  819. @@  -­‐56,14  +56,8  @@  SELECT  throws_ok(        

       'Should  get  an  error  for  duplicate  nickname'    );       -­‐SELECT  bag_eq(   -­‐        'SELECT  *  FROM  users',   -­‐        $$  VALUES   -­‐                ('theory',        md5('foo'),    NOW()),   -­‐                ('strongrrl',  md5('w00t'),  NOW())   -­‐        $$,   -­‐        'Should  still  have  just  the  two  users'   -­‐);   +SELECT  is(COUNT(*)::INT,  2,  'Should  still  have  two  users')   +    FROM  flipr.users;        SELECT  finish();    ROLLBACK;   >
  820. @@  -­‐56,14  +56,8  @@  SELECT  throws_ok(        

       'Should  get  an  error  for  duplicate  nickname'    );       -­‐SELECT  bag_eq(   -­‐        'SELECT  *  FROM  users',   -­‐        $$  VALUES   -­‐                ('theory',        md5('foo'),    NOW()),   -­‐                ('strongrrl',  md5('w00t'),  NOW())   -­‐        $$,   -­‐        'Should  still  have  just  the  two  users'   -­‐);   +SELECT  is(COUNT(*)::INT,  2,  'Should  still  have  two  users')   +    FROM  flipr.users;        SELECT  finish();    ROLLBACK;   >
  821. FAIL >

  822. FAIL >  pg_prove  -­‐d  flipr_test  test/insert_user.sql #  Failed  test  7:

     "The  user  should  have  been  inserted" #  Failed  test  10:  "The  second  user  should  have  been  inserted" #  Looks  like  you  failed  2  tests  of  12 test/insert_user.sql  ..  Failed  2/12  subtests   Test  Summary  Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ test/insert_user.sql  (Wstat:  0  Tests:  12  Failed:  2)    Failed  tests:    7,  10 Files=1,  Tests=12,    0  wallclock  secs Result:  FAIL >
  823. FAIL >  pg_prove  -­‐d  flipr_test  test/insert_user.sql #  Failed  test  7:

     "The  user  should  have  been  inserted" #  Failed  test  10:  "The  second  user  should  have  been  inserted" #  Looks  like  you  failed  2  tests  of  12 test/insert_user.sql  ..  Failed  2/12  subtests   Test  Summary  Report -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ test/insert_user.sql  (Wstat:  0  Tests:  12  Failed:  2)    Failed  tests:    7,  10 Files=1,  Tests=12,    0  wallclock  secs Result:  FAIL > As expected.
  824. Back when discussing traditional migration systems, I said… antisocial network

  825. Managing procedures is a PITA! antisocial network

  826. Consider this Change >

  827. Consider this Change    git  diff  deploy   diff  -­‐-­‐git

     a/deploy/insert_user.sql  b/deploy/insert_user.sql index  eb30fed..5c28d02  100644 -­‐-­‐-­‐  a/deploy/insert_user.sql +++  b/deploy/insert_user.sql @@  -­‐8,7  +8,7  @@  CREATE  OR  REPLACE  FUNCTION  flipr.insert_user(          nickname  TEXT,          password  TEXT  )  RETURNS  VOID  LANGUAGE  SQL  SECURITY  DEFINER  AS  $$ -­‐        INSERT  INTO  flipr.users  VALUES($1,  md5($2)); +        INSERT  INTO  flipr.users  values($1,  crypt($2,  gen_salt('md5')));  $$;    COMMIT; > >
  828. Consider this Change    git  diff  deploy   diff  -­‐-­‐git

     a/deploy/insert_user.sql  b/deploy/insert_user.sql index  eb30fed..5c28d02  100644 -­‐-­‐-­‐  a/deploy/insert_user.sql +++  b/deploy/insert_user.sql @@  -­‐8,7  +8,7  @@  CREATE  OR  REPLACE  FUNCTION  flipr.insert_user(          nickname  TEXT,          password  TEXT  )  RETURNS  VOID  LANGUAGE  SQL  SECURITY  DEFINER  AS  $$ -­‐        INSERT  INTO  flipr.users  VALUES($1,  md5($2)); +        INSERT  INTO  flipr.users  values($1,  crypt($2,  gen_salt('md5')));  $$;    COMMIT; > > Simple, right?
  829. Not So Much antisocial network

  830. Not So Much Copy insert_user.sql to new deploy file antisocial

    network
  831. Not So Much Copy insert_user.sql to new deploy file Change

    that new file antisocial network
  832. Not So Much Copy insert_user.sql to new deploy file Change

    that new file Copy insert_user.sql to new revert file antisocial network
  833. Not So Much Copy insert_user.sql to new deploy file Change

    that new file Copy insert_user.sql to new revert file Test it antisocial network
  834. Not So Much Copy insert_user.sql to new deploy file Change

    that new file Copy insert_user.sql to new revert file Test it Do the same for change_pass.sql antisocial network
  835. Not So Much Copy insert_user.sql to new deploy file Change

    that new file Copy insert_user.sql to new revert file Test it Do the same for change_pass.sql The problem with that… antisocial network
  836. >

  837. >  git  diff  HEAD^ diff  -­‐-­‐git  a/deploy/insert_user_crypt.sql  b/deploy/insert_user_crypto.sql new  file

     mode  100644 index  0000000..fa8d0c6 -­‐-­‐-­‐  /dev/null +++  b/deploy/insert_user_crypt.sql @@  -­‐0,0  +1,8  @@ +-­‐-­‐  requires:  users,  appuser,  pgcrypto + +CREATE  OR  REPLACE  FUNCTION  insert_user( +        nickname  TEXT, +        password  TEXT +)  RETURNS  VOID  LANGUAGE  SQL  AS  $$ +        INSERT  INTO  users  values($1,  crypt($2,  gen_salt('md5'))); +$$; diff  -­‐-­‐git  a/revert/insert_user_crypt.sql  b/revert/insert_user_crypto.sql new  file  mode  100644 index  0000000..a7f4e31 -­‐-­‐-­‐  /dev/null +++  b/revert/insert_user_crypt.sql @@  -­‐0,0  +1,8  @@ +-­‐-­‐  requires:  users,  appuser + +CREATE  OR  REPLACE  FUNCTION  insert_user( +        nickname  TEXT, +        password  TEXT +)  RETURNS  VOID  LANGUAGE  SQL  AS  $$ +        INSERT  INTO  users  values($1,  md5($2)); +$$; >
  838. >  git  diff  HEAD^ diff  -­‐-­‐git  a/deploy/insert_user_crypt.sql  b/deploy/insert_user_crypto.sql new  file

     mode  100644 index  0000000..fa8d0c6 -­‐-­‐-­‐  /dev/null +++  b/deploy/insert_user_crypt.sql @@  -­‐0,0  +1,8  @@ +-­‐-­‐  requires:  users,  appuser,  pgcrypto + +CREATE  OR  REPLACE  FUNCTION  insert_user( +        nickname  TEXT, +        password  TEXT +)  RETURNS  VOID  LANGUAGE  SQL  AS  $$ +        INSERT  INTO  users  values($1,  crypt($2,  gen_salt('md5'))); +$$; diff  -­‐-­‐git  a/revert/insert_user_crypt.sql  b/revert/insert_user_crypto.sql new  file  mode  100644 index  0000000..a7f4e31 -­‐-­‐-­‐  /dev/null +++  b/revert/insert_user_crypt.sql @@  -­‐0,0  +1,8  @@ +-­‐-­‐  requires:  users,  appuser + +CREATE  OR  REPLACE  FUNCTION  insert_user( +        nickname  TEXT, +        password  TEXT +)  RETURNS  VOID  LANGUAGE  SQL  AS  $$ +        INSERT  INTO  users  values($1,  md5($2)); +$$; > Oy.
  839. Let Sqitch do the work. antisocial network

  840. Rework It >

  841.    sqitch  rework  insert_user  -­‐r  pgcrypto  \    -­‐n  'Changes

     insert_user  to  use  pgcrypto.' Added  "insert_user  [insert_user@v1.0.0-­‐r1  pgcrypto]"  to   sqitch.plan. Modify  these  files  as  appropriate:    *  deploy/insert_user.sql    *  revert/insert_user.sql    *  verify/insert_user.sql > Rework It >
  842.    sqitch  rework  insert_user  -­‐r  pgcrypto  \    -­‐n  'Changes

     insert_user  to  use  pgcrypto.' Added  "insert_user  [insert_user@v1.0.0-­‐r1  pgcrypto]"  to   sqitch.plan. Modify  these  files  as  appropriate:    *  deploy/insert_user.sql    *  revert/insert_user.sql    *  verify/insert_user.sql > Rework It >
  843.    sqitch  rework  insert_user  -­‐r  pgcrypto  \    -­‐n  'Changes

     insert_user  to  use  pgcrypto.' Added  "insert_user  [insert_user@v1.0.0-­‐r1  pgcrypto]"  to   sqitch.plan. Modify  these  files  as  appropriate:    *  deploy/insert_user.sql    *  revert/insert_user.sql    *  verify/insert_user.sql > Rework It >
  844.    sqitch  rework  insert_user  -­‐r  pgcrypto  \    -­‐n  'Changes

     insert_user  to  use  pgcrypto.' Added  "insert_user  [insert_user@v1.0.0-­‐r1  pgcrypto]"  to   sqitch.plan. Modify  these  files  as  appropriate:    *  deploy/insert_user.sql    *  revert/insert_user.sql    *  verify/insert_user.sql > Rework It > Same files?
  845. Same Files? >

  846.    git  status #  On  branch  master #  Changes  not

     staged  for  commit: #      (use  "git  add  <file>..."  to  update  what  will  be  committe #      (use  "git  checkout  -­‐-­‐  <file>..."  to  discard  changes  in  w # #   modified:      revert/insert_user.sql #   modified:      sqitch.plan #   modified:      test/insert_user.sql # #  Untracked  files: #      (use  "git  add  <file>..."  to  include  in  what  will  be  comm # #   deploy/insert_user@v1.0.0-­‐r1.sql #   revert/insert_user@v1.0.0-­‐r1.sql #   verify/insert_user@v1.0.0-­‐r1.sql no  changes  added  to  commit  (use  "git  add"  and/or  "git  commit > Same Files? >
  847.    git  status #  On  branch  master #  Changes  not

     staged  for  commit: #      (use  "git  add  <file>..."  to  update  what  will  be  committe #      (use  "git  checkout  -­‐-­‐  <file>..."  to  discard  changes  in  w # #   modified:      revert/insert_user.sql #   modified:      sqitch.plan #   modified:      test/insert_user.sql # #  Untracked  files: #      (use  "git  add  <file>..."  to  include  in  what  will  be  comm # #   deploy/insert_user@v1.0.0-­‐r1.sql #   revert/insert_user@v1.0.0-­‐r1.sql #   verify/insert_user@v1.0.0-­‐r1.sql no  changes  added  to  commit  (use  "git  add"  and/or  "git  commit > Same Files? >
  848.    git  status #  On  branch  master #  Changes  not

     staged  for  commit: #      (use  "git  add  <file>..."  to  update  what  will  be  committe #      (use  "git  checkout  -­‐-­‐  <file>..."  to  discard  changes  in  w # #   modified:      revert/insert_user.sql #   modified:      sqitch.plan #   modified:      test/insert_user.sql # #  Untracked  files: #      (use  "git  add  <file>..."  to  include  in  what  will  be  comm # #   deploy/insert_user@v1.0.0-­‐r1.sql #   revert/insert_user@v1.0.0-­‐r1.sql #   verify/insert_user@v1.0.0-­‐r1.sql no  changes  added  to  commit  (use  "git  add"  and/or  "git  commit > Same Files? > As of @v1.0.0-r1
  849.    git  status #  On  branch  master #  Changes  not

     staged  for  commit: #      (use  "git  add  <file>..."  to  update  what  will  be  committe #      (use  "git  checkout  -­‐-­‐  <file>..."  to  discard  changes  in  w # #   modified:      revert/insert_user.sql #   modified:      sqitch.plan #   modified:      test/insert_user.sql # #  Untracked  files: #      (use  "git  add  <file>..."  to  include  in  what  will  be  comm # #   deploy/insert_user@v1.0.0-­‐r1.sql #   revert/insert_user@v1.0.0-­‐r1.sql #   verify/insert_user@v1.0.0-­‐r1.sql no  changes  added  to  commit  (use  "git  add"  and/or  "git  commit > Same Files? > Previous deploy becomes revert
  850. What’s the Diff? >

  851. What’s the Diff?    git  diff  deploy/insert_user.sql diff  -­‐-­‐git  a/deploy/insert_user.sql

     b/deploy/insert_user.sql @@  -­‐1,6  +1,7  @@  -­‐-­‐  Deploy  insert_user  -­‐-­‐  requires:  users  -­‐-­‐  requires:  appschema +-­‐-­‐  requires:  pgcrypto    BEGIN;   @@  -­‐8,7  +9,7  @@  CREATE  OR  REPLACE  FUNCTION  flipr.insert_user(          nickname  TEXT,          password  TEXT  )  RETURNS  VOID  LANGUAGE  SQL  SECURITY  DEFINER  AS  $$ -­‐        INSERT  INTO  flipr.users  VALUES($1,  md5($2)); +        INSERT  INTO  flipr.users  values($1,  crypt($2,  gen_salt('md5')));  $$;    COMMIT; >
  852. Send it Up! >

  853. Send it Up! >  sqitch  deploy Deploying  changes  to  flipr_test

       +  insert_user  ..  ok > >
  854. >  psql  -­‐d  flipr_test  -­‐c  "        DELETE

     FROM  flipr.users;        SELECT  flipr.insert_user('foo',  'secr3t'),                      flipr.insert_user('bar',  'secr3t');        SELECT  nickname,  password  FROM  flipr.users; "  nickname  |                            password                             -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐  foo            |  $1$nKO47p03$YRXYTt4NoNncTThLyxzEq1  bar            |  $1$LbVUs/p.$LVbvPlkD8rJlixW2nS3WP0 (2  rows) > Send it Up! >  sqitch  deploy Deploying  changes  to  flipr_test    +  insert_user  ..  ok > >
  855. >  psql  -­‐d  flipr_test  -­‐c  "        DELETE

     FROM  flipr.users;        SELECT  flipr.insert_user('foo',  'secr3t'),                      flipr.insert_user('bar',  'secr3t');        SELECT  nickname,  password  FROM  flipr.users; "  nickname  |                            password                             -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐  foo            |  $1$nKO47p03$YRXYTt4NoNncTThLyxzEq1  bar            |  $1$LbVUs/p.$LVbvPlkD8rJlixW2nS3WP0 (2  rows) > Send it Up! >  sqitch  deploy Deploying  changes  to  flipr_test    +  insert_user  ..  ok > > \o/
  856. Can We Go Back? >

  857. Can We Go Back? >  sqitch  revert  -­‐-­‐to  @HEAD^  -­‐y

       -­‐  insert_user  ..  ok > >
  858.    psql  -­‐d  flipr_test  -­‐c  "        DELETE

     FROM  flipr.users;        SELECT  flipr.insert_user('foo',  'secr3t'),                      flipr.insert_user('bar',  'secr3t');        SELECT  nickname,  password  FROM  flipr.users; "  nickname  |                          password                           -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐+-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐  foo            |  9695da4dd567a19f9b92065f240c6725  bar            |  9695da4dd567a19f9b92065f240c6725 (2  rows) Can We Go Back? >  sqitch  revert  -­‐-­‐to  @HEAD^  -­‐y    -­‐  insert_user  ..  ok > >
  859. Verify How? >

  860. Verify How? >  emacs  verify/insert_user.sql > >

  861. -­‐-­‐  Verify  insert_user   ! BEGIN; SELECT  has_function_privilege(    

         'flipr.insert_user(text,  text)',          'execute'   ); verify/insert_u verify/insert_user.sql COMMIT;
  862. SELECT  1/COUNT(*)    FROM  pg_catalog.pg_proc  WHERE  proname  =  'insert_user'  

       AND  pg_get_functiondef(oid)              LIKE  $$%crypt($2,  gen_salt('md5'))%$$; -­‐-­‐  Verify  insert_user   ! BEGIN; SELECT  has_function_privilege(          'flipr.insert_user(text,  text)',          'execute'   ); verify/insert_u verify/insert_user.sql COMMIT;
  863. SELECT  1/COUNT(*)    FROM  pg_catalog.pg_proc  WHERE  proname  =  'insert_user'  

       AND  pg_get_functiondef(oid)              LIKE  $$%crypt($2,  gen_salt('md5'))%$$; -­‐-­‐  Verify  insert_user   ! BEGIN; SELECT  has_function_privilege(          'flipr.insert_user(text,  text)',          'execute'   ); verify/insert_u verify/insert_user.sql COMMIT; Yeah, compare source.
  864. >  emacs  verify/insert_user.sql   > Let’s Go!

  865. >  emacs  verify/insert_user.sql   > Let’s Go! >  sqitch  deploy

    Deploying  changes  to  flipr_test    +  insert_user  ..  ok >
  866. >  emacs  verify/insert_user.sql   > Let’s Go! >  sqitch  deploy

    Deploying  changes  to  flipr_test    +  insert_user  ..  ok > >  psql  -­‐d  flipr_test  -­‐c  'DELETE  FROM  flipr.users' DELETE  2 >
  867. >  emacs  verify/insert_user.sql   > Let’s Go! >  sqitch  deploy

    Deploying  changes  to  flipr_test    +  insert_user  ..  ok > >  psql  -­‐d  flipr_test  -­‐c  'DELETE  FROM  flipr.users' DELETE  2 >    pg_prove  -­‐d  flipr_test  test/insert_user.sql         test/insert_user.sql  ..  ok           All  tests  successful. Files=1,  Tests=12,    0  wallclock  secs Result:  PASS > Shazam!
  868. Add, Commit, Push, Go >

  869.    git  add  . >  git  commit  -­‐m  'Update  insert_user

     to  use  pgcrypto.' [master  e4edde6]  Update  insert_user  to  use  pgcrypto.  8  files  changed,  64  insertions(+),  24  deletions(-­‐)  create  mode  100644  deploy/insert_user@v1.0.0-­‐r1.sql  create  mode  100644  revert/insert_user@v1.0.0-­‐r1.sql  create  mode  100644  verify/insert_user@v1.0.0-­‐r1.sql > Add, Commit, Push, Go >
  870.    git  add  . >  git  commit  -­‐m  'Update  insert_user

     to  use  pgcrypto.' [master  e4edde6]  Update  insert_user  to  use  pgcrypto.  8  files  changed,  64  insertions(+),  24  deletions(-­‐)  create  mode  100644  deploy/insert_user@v1.0.0-­‐r1.sql  create  mode  100644  revert/insert_user@v1.0.0-­‐r1.sql  create  mode  100644  verify/insert_user@v1.0.0-­‐r1.sql > Add, Commit, Push, Go >  git  push Counting  objects:  17,  done. Delta  compression  using  up  to  4  threads. Compressing  objects:  100%  (10/10),  done. Writing  objects:  100%  (10/10),  1.77  KiB,  done. Total  10  (delta  6),  reused  0  (delta  0) To  https://github.com/theory/agile-­‐flipr.git      9a9f1da..e4edde6    master  -­‐>  master > >
  871. antisocial network Change It Up

  872. antisocial network Change It Up git reset --hard insert_user2

  873. antisocial network Change It Up git reset --hard insert_user2 Rework

    change_pass
  874. antisocial network Change It Up git reset --hard insert_user2 Rework

    change_pass Use pgcrypo
  875. antisocial network Change It Up git reset --hard insert_user2 Rework

    change_pass Use pgcrypo Test first!
  876. antisocial network Change It Up git reset --hard insert_user2 Rework

    change_pass Use pgcrypo Test first! Bundle, tag, release
  877. antisocial network Change It Up git reset --hard insert_user2 Rework

    change_pass Use pgcrypo Test first! Bundle, tag, release https:/ /github.com/ theory/agile-flipr.git
  878. I’m afraid I have some bad news… antisocial network

  879. None
  880. Antisocial Networking Startup Flipr Heads To The Deadpool by Michael

    Arrington on November 2, 2010 antisocial network I loved this site. Flipr, an online “antisocial networking” site that encouraged users to alienate each other in order to increase their antisocial cred, is shutting down. The startup’s homepage now consists of a letter to Flipr users instructing them to download their “flips” by November 30, at which point nearly all of the service’s features will be taken offline and data deleted. In the letter, Flipr CEO David Wheeler writes that despite ample venture funding and a dedicated team of database developers, the site underestimated people’s willingness to be assholes. This is not something I can relate to, although from what I’ve been told by more polite society, it is indeed the case. Such a shame.
  881. I’m afraid it’s true. antisocial network RIP

  882. I’m sorry I have no money left to pay you.

    antisocial network RIP
  883. I hope you enjoyed working here. antisocial network RIP

  884. And that you’re able to use the skills you’ve gained

    in your next job. antisocial network RIP
  885. Git Skillz antisocial network RIP

  886. Git Skillz Branching antisocial network RIP

  887. Git Skillz Branching Diffing antisocial network RIP

  888. Git Skillz Branching Diffing Rebasing antisocial network RIP

  889. Git Skillz Branching Diffing Rebasing Merging antisocial network RIP

  890. Git Skillz Branching Diffing Rebasing Merging Committing antisocial network RIP

  891. Git Skillz Branching Diffing Rebasing Merging Committing Pushing antisocial network

    RIP
  892. MOAR Git antisocial network RIP

  893. MOAR Git Bisecting antisocial network RIP

  894. MOAR Git Bisecting Blaming antisocial network RIP

  895. MOAR Git Bisecting Blaming Pull requests antisocial network RIP

  896. MOAR Git Bisecting Blaming Pull requests Submitting patches antisocial network

    RIP
  897. MOAR Git Bisecting Blaming Pull requests Submitting patches Rewriting history

    antisocial network RIP
  898. MOAR Git Bisecting Blaming Pull requests Submitting patches Rewriting history

    Log formatting antisocial network RIP
  899. MOAR Git Bisecting Blaming Pull requests Submitting patches Rewriting history

    Log formatting git help --all antisocial network RIP
  900. pgTAP Skillz antisocial network RIP

  901. pgTAP Skillz TDDD antisocial network RIP

  902. pgTAP Skillz TDDD Schema testing antisocial network RIP

  903. pgTAP Skillz TDDD Schema testing Scalar testing antisocial network RIP

  904. pgTAP Skillz TDDD Schema testing Scalar testing Functional testing antisocial

    network RIP
  905. pgTAP Skillz TDDD Schema testing Scalar testing Functional testing Relational

    testing antisocial network RIP
  906. MOAR pgTAP antisocial network RIP

  907. MOAR pgTAP Testing privileges antisocial network RIP

  908. MOAR pgTAP Testing privileges Mocking interfaces antisocial network RIP

  909. MOAR pgTAP Testing privileges Mocking interfaces Custom test functions antisocial

    network RIP
  910. MOAR pgTAP Testing privileges Mocking interfaces Custom test functions xUnit-style

    testing antisocial network RIP
  911. MOAR pgTAP Testing privileges Mocking interfaces Custom test functions xUnit-style

    testing Tests maintained in functions antisocial network RIP
  912. MOAR pgTAP Testing privileges Mocking interfaces Custom test functions xUnit-style

    testing Tests maintained in functions http:/ /pgtap.org/documentation.html antisocial network RIP
  913. Sqitch Skillz antisocial network RIP

  914. Sqitch Skillz Add changes antisocial network RIP

  915. Sqitch Skillz Add changes Specify Dependencies antisocial network RIP

  916. Sqitch Skillz Add changes Specify Dependencies Manage targets antisocial network

    RIP
  917. Sqitch Skillz Add changes Specify Dependencies Manage targets Deploy, Verify,

    Revert changes antisocial network RIP
  918. Sqitch Skillz Add changes Specify Dependencies Manage targets Deploy, Verify,

    Revert changes Rebase changes antisocial network RIP
  919. Sqitch Skillz Add changes Specify Dependencies Manage targets Deploy, Verify,

    Revert changes Rebase changes Rework changes antisocial network RIP
  920. Sqitch Skillz Add changes Specify Dependencies Manage targets Deploy, Verify,

    Revert changes Rebase changes Rework changes Changing branches antisocial network RIP
  921. MOAR Sqitch antisocial network RIP

  922. MOAR Sqitch Cross-project dependencies antisocial network RIP

  923. MOAR Sqitch Cross-project dependencies Multiple projects, one database antisocial network

    RIP
  924. MOAR Sqitch Cross-project dependencies Multiple projects, one database Script templating

    antisocial network RIP
  925. MOAR Sqitch Cross-project dependencies Multiple projects, one database Script templating

    Variables, loops, conditionals antisocial network RIP
  926. MOAR Sqitch Cross-project dependencies Multiple projects, one database Script templating

    Variables, loops, conditionals Logging antisocial network RIP
  927. MOAR Sqitch Cross-project dependencies Multiple projects, one database Script templating

    Variables, loops, conditionals Logging Formatting output antisocial network RIP
  928. MOAR Sqitch Cross-project dependencies Multiple projects, one database Script templating

    Variables, loops, conditionals Logging Formatting output sqitch help antisocial network RIP
  929. Good luck out there. antisocial network RIP

  930. Agile Database Development David E. Wheeler ! ! ! January

    2014 Portland Text: Attribution-Noncommercial-Share Alike 3.0 United States: http:/ /creativecommons.org/licenses/by-nc-sa/3.0/us/ Images licensed independently and © Their respective owners. iovation