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

Agile Database Development 3ed

Agile Database Development 3ed

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), database unit testing (pgTAP), and database change management and deployment (Sqitch). 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, 2ed January 2014, 3ed January 2016.

397f829eea921e02e35c37c22f9e6d3b?s=128

David E. Wheeler

January 29, 2016
Tweet

Transcript

  1. Agile Database Development David E. Wheeler 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. sqitch.org iovation January 28, 2016
  2. Agile Database Development David E. Wheeler 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. ✘ sqitch.org iovation January 28, 2016
  3. David E. Wheeler 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.
  4. David E. Wheeler License: Attribution-Noncommercial-Share Alike 3.0 United States: http:/

    /creativecommons.org/licenses/by-nc-sa/3.0/us/
  5. Build My VC-Funded App for Me for Free David E.

    Wheeler License: Attribution-Noncommercial-Share Alike 3.0 United States: http:/ /creativecommons.org/licenses/by-nc-sa/3.0/us/ ✔ CEO, Data Architect Agile Archapelago, Inc.
  6. This is Genius

  7. This is Genius I had this idea

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

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

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

    HAWT Has been for waaaay too long The backlash is long overdue
  11. 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
  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 Introducing…
  13. http:/ /flic.kr/p/8j5gG8 © 2010 Strongrrl. All rights reserved. Used with

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

    Used with permission.
  15. How it Works antisocial network

  16. How it Works Microblogging platform antisocial network

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

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

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

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

    follow everyone Goal: Alienate your followers Get them to unfollow you antisocial network
  21. 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
  22. Your Task antisocial network

  23. Your Task Create the database antisocial network

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

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

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

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

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

    Used with permission.
  29. But first… antisocial network

  30. NDA antisocial network

  31. Job Requirements antisocial network

  32. Job Requirements PostgreSQL Should be installed antisocial network

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

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

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

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

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

  38. Let’s do this thang. antisocial network

  39. > Who Am I?

  40. git config --global user.name 'David E. Wheeler' > > Who

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

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

    --global user.email david@justatheory.com > > 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? Please use your own name and email.
  45. git config --global user.name 'David E. Wheeler' > git config

    --global user.email david@justatheory.com > > Who Am I? emacs ~/.gitconfig >
  46. ~/.gitconfig ~/ .gitconfig [user] name = David E. Wheeler email

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

    = david@justatheory.com Good for all projects
  48. Create a Remote

  49. Create a Remote Create Git project in Stash

  50. Create a Remote Create Git project in Stash Or GitHub

    or BitBucket
  51. Create a Remote Create Git project in Stash Or GitHub

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

    or BitBucket Wherever you like Record remote URL
  53. Create a Remote Create Git project in Stash Or GitHub

    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 origin --set-upstream master Counting objects: 3, done. Writing

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

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

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

    objects: 100% (3/3), 260 bytes, done. Total 3 (delta 0), reused 0 (delta 0) To ssh://git@source.iovationnp.com:7999/~david.wheeler/ agile-flipr.git * [new branch] master -> master Branch master set up to track remote branch master from origin. > 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] appschema -> upstream/appschema * [new branch] change_pass -> upstream/change_pass * [new branch] flips -> upstream/flips * [new branch] insert_user -> upstream/insert_user * [new branch] insert_user2 -> upstream/insert_user2 * [new branch] master -> upstream/master * [new branch] reltag -> upstream/reltag * [new branch] userfuncs -> upstream/userfuncs * [new branch] users -> upstream/users >
  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] appschema -> upstream/appschema * [new branch] change_pass -> upstream/change_pass * [new branch] flips -> upstream/flips * [new branch] insert_user -> upstream/insert_user * [new branch] insert_user2 -> upstream/insert_user2 * [new branch] master -> upstream/master * [new branch] reltag -> upstream/reltag * [new branch] userfuncs -> upstream/userfuncs * [new branch] users -> upstream/users > 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 Push to remote (origin, upstream) antisocial network
  77. Git? Manage tree of files over time Distributed development Commit

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

    changes locally Push 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> 1453941938 -0800 committer David Wheeler <david@justatheory.com> 1453941938 -0800 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> 1453941938 -0800 committer David Wheeler <david@justatheory.com> 1453941938 -0800 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> 1453941938 -0800 committer David Wheeler <david@justatheory.com> 1453941938 -0800 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> 1453941938 -0800 committer David Wheeler <david@justatheory.com> 1453941938 -0800 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> 1453941938 -0800 committer David Wheeler <david@justatheory.com> 1453941938 -0800 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> 1453941938 -0800 committer David Wheeler <david@justatheory.com> 1453941938 -0800 Get through "Ship it!". > Making a hash of it
  102. SHAzam! antisocial network

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

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

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

    any commit to the beginning Tampering (corruption) detectable antisocial network
  106. SHAzam! Each commit (except root) 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 root) 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. SHAzam! Each commit (except root) 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/ Also: Bitcoin Blockchain antisocial network
  109. antisocial network Your Turn

  110. antisocial network Your Turn Configure Git

  111. antisocial network Your Turn Configure Git Initialize repository

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

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

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

    remote Add upstream remote https:/ /github.com/ theory/agile-flipr.git
  115. antisocial network Your Turn Configure Git Initialize repository Add origin

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

  117. Who am I again? > sqitch config --user user.name 'David

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

    E. Wheeler' >
  119. sqitch config --user user.email david@justatheory.com > Who am I again?

    > sqitch config --user user.name 'David E. Wheeler' >
  120. sqitch config --user user.email david@justatheory.com > > Who am I

    again? > sqitch config --user user.name 'David E. Wheeler' > emacs ~/.sqitch/sqitch.conf >
  121. ~/.sqitch/sqitc ~/ .sqitch/sqitch.conf [core "pg"] client = /opt/local/pgsql/bin/psql [user] name

    = David E. Wheeler email = david@justatheory.com
  122. ~/.sqitch/sqitc ~/ .sqitch/sqitch.conf [core "pg"] client = /opt/local/pgsql/bin/psql [user] name

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

  124. > sqitch init flipr --engine pg \ --uri file://../flipr-remote Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch
  125. > sqitch init flipr --engine pg \ --uri file://../flipr-remote Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch
  126. > sqitch init flipr --engine pg \ --uri file://../flipr-remote Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch Use remote URL
  127. > sqitch init flipr --engine pg \ --uri file://../flipr-remote Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch
  128. > sqitch init flipr --engine pg \ --uri file://../flipr-remote Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch
  129. > sqitch init flipr --engine pg \ --uri file://../flipr-remote Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch
  130. > sqitch init flipr --engine pg \ --uri file://../flipr-remote Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch
  131. > sqitch init flipr --engine pg \ --uri file://../flipr-remote Created

    sqitch.conf Created sqitch.plan Created deploy/ Created revert/ Created verify/ > > Scratch that Sqitch
  132. > sqitch init flipr --engine pg \ --uri file://../flipr-remote Created

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

    # top_dir = . # [engine "pg"] # target = db:pg: # registry = sqitch # client = /usr/local/pgsql/bin/psql
  134. sqitch.conf sqitch.conf [core] engine = pg # plan_file = sqitch.plan

    # top_dir = . # [engine "pg"] # target = db:pg: # registry = sqitch # client = /usr/local/pgsql/bin/psql --engine pg
  135. What’s the Plan Man? >

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

  137. sqitch.plan sqitch.plan %syntax-version=1.0.0 %project=flipr %uri=file://../flipr-remote

  138. sqitch.plan sqitch.plan %syntax-version=1.0.0 %project=flipr %uri=file://../flipr-remote Identified

  139. Make It So >

  140. Make It So > git add . > git commit

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

    -m 'Initialize Sqitch configuration.' [master 297c07d] Initialize Sqitch configuration. 2 files changed, 20 insertions(+) create mode 100644 sqitch.conf create mode 100644 sqitch.plan >
  142. Make It So > git add . > git commit

    -m 'Initialize Sqitch configuration.' [master 297c07d] Initialize Sqitch configuration. 2 files changed, 20 insertions(+) create mode 100644 sqitch.conf create mode 100644 sqitch.plan >
  143. Make It So > git add . > git commit

    -m 'Initialize Sqitch configuration.' [master 297c07d] Initialize Sqitch configuration. 2 files changed, 20 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), 564 bytes, done. Total 4 (delta 0), reused 0 (delta 0) To ../flipr-remote 7d28be0..297c07d master -> master >
  144. Make It So > git add . > git commit

    -m 'Initialize Sqitch configuration.' [master 297c07d] Initialize Sqitch configuration. 2 files changed, 20 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), 564 bytes, done. Total 4 (delta 0), reused 0 (delta 0) To ../flipr-remote 7d28be0..297c07d master -> master >
  145. Make It So > git add . > git commit

    -m 'Initialize Sqitch configuration.' [master 297c07d] Initialize Sqitch configuration. 2 files changed, 20 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), 564 bytes, done. Total 4 (delta 0), reused 0 (delta 0) To ../flipr-remote 7d28be0..297c07d master -> master >
  146. Where’ve We Been? >

  147. git log commit a4f765f88c1875ffe9427e73f72a6b66c297c07d Author: David E. Wheeler <david@justatheory.com> Date:

    Tue Jan 26 14:34:01 2016 -0800 Initialize Sqitch configuration. commit 2c4b51017929634a30f4a74e20268c05e7d28be0 Author: David E. Wheeler <david@justatheory.com> Date: Tue Jan 26 13:28:09 2016 -0800 Initialize repo, add README. > Where’ve We Been? >
  148. git log commit a4f765f88c1875ffe9427e73f72a6b66c297c07d Author: David E. Wheeler <david@justatheory.com> Date:

    Tue Jan 26 14:34:01 2016 -0800 Initialize Sqitch configuration. commit 2c4b51017929634a30f4a74e20268c05e7d28be0 Author: David E. Wheeler <david@justatheory.com> Date: Tue Jan 26 13:28:09 2016 -0800 Initialize repo, add README. > Where’ve We Been? >
  149. git log commit a4f765f88c1875ffe9427e73f72a6b66c297c07d Author: David E. Wheeler <david@justatheory.com> Date:

    Tue Jan 26 14:34:01 2016 -0800 Initialize Sqitch configuration. commit 2c4b51017929634a30f4a74e20268c05e7d28be0 Author: David E. Wheeler <david@justatheory.com> Date: Tue Jan 26 13:28:09 2016 -0800 Initialize repo, add README. > Where’ve We Been? >
  150. First Change >

  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 > >
  153. 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 > >
  154. 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 >
  155. deploy/appschem deploy/appschema.sql -- Deploy flipr:appschema to pg BEGIN; COMMIT; --

    XXX Add DDLs here.
  156. deploy/appschem deploy/appschema.sql -- Deploy flipr:appschema to pg BEGIN; COMMIT; CREATE

    SCHEMA flipr;
  157. > 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 >
  158. > 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 >
  159. revert/appschem revert/appschema.sql -- Revert flipr:appschema from pg BEGIN; COMMIT; --

    XXX Add DDLs here.
  160. revert/appschem revert/appschema.sql -- Revert flipr:appschema from pg BEGIN; COMMIT; DROP

    SCHEMA flipr;
  161. Make it So! >

  162. createdb flipr_test > 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 > 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! > Might need -U postgres
  164. createdb flipr_test > 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 > 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 > 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! >
  167. createdb flipr_test > 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! >
  168. createdb flipr_test > 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 >
  169. createdb flipr_test > 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
  170. createdb flipr_test > 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
  171. -- Verify flipr:appschema on pg BEGIN; ROLLBACK; verify/appschem verify/appschema.sql --

    XXX Add verifications here.
  172. -- Verify flipr:appschema on pg BEGIN; ROLLBACK; SELECT pg_catalog.has_schema_privilege('nada', 'usage');

    verify/appschem verify/appschema.sql
  173. -- Verify flipr:appschema on pg BEGIN; ROLLBACK; SELECT pg_catalog.has_schema_privilege('nada', 'usage');

    verify/appschem verify/appschema.sql Let’s try it, first
  174. Trust, But Verify > emacs verify/appschema.sql >

  175. Trust, But Verify > 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 >
  176. Trust, But Verify > 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 >
  177. Trust, But Verify > 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 >
  178. Trust, But Verify > 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 >
  179. Trust, But Verify >

  180. perl -i -pe 's/nada/flipr/' verify/appschema.sql > Trust, But Verify >

  181. 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.
  182. > How’s it Look?

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

    database db:pg:flipr_test # Project: flipr # Change: 748346dfe73cf2af32a8b7088fd75ad8d7aecda3 # Name: appschema # Deployed: 2016-01-26 14:49:54 -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: 748346dfe73cf2af32a8b7088fd75ad8d7aecda3 # Name: appschema # Deployed: 2016-01-26 14:49:54 -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: 748346dfe73cf2af32a8b7088fd75ad8d7aecda3 # Name: appschema # Deployed: 2016-01-26 14:49:54 -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: 748346dfe73cf2af32a8b7088fd75ad8d7aecda3 # Name: appschema # Deployed: 2016-01-26 14:49:54 -0800 # By: David E. Wheeler <david@justatheory.com> # Nothing to deploy (up-to-date) >
  187. > How’s it Look? > sqitch status db:pg:flipr_test # On

    database db:pg:flipr_test # Project: flipr # Change: 748346dfe73cf2af32a8b7088fd75ad8d7aecda3 # Name: appschema # Deployed: 2016-01-26 14:49:54 -0800 # By: David E. Wheeler <david@justatheory.com> # Nothing to deploy (up-to-date) >
  188. > How’s it Look? > sqitch status db:pg:flipr_test # On

    database db:pg:flipr_test # Project: flipr # Change: 748346dfe73cf2af32a8b7088fd75ad8d7aecda3 # Name: appschema # Deployed: 2016-01-26 14:49:54 -0800 # By: David E. Wheeler <david@justatheory.com> # Nothing to deploy (up-to-date) >
  189. Go Back >

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

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

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

    Go Back > - appschema .. ok >
  193. > 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 >
  194. > 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 >
  195. History >

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

    748346dfe73cf2af32a8b7088fd75ad8d7aecda3 Name: appschema Committer: David E. Wheeler <david@justatheory.com> Date: 2016-01-26 15:35:04 -0800 Adds flipr app schema. Deploy 748346dfe73cf2af32a8b7088fd75ad8d7aecda3 Name: appschema Committer: David E. Wheeler <david@justatheory.com> Date: 2016-01-26 14:49:54 -0800 Adds flipr app schema.
  197. History > > sqitch log db:pg:flipr_test On database db:pg:flipr_test Revert

    748346dfe73cf2af32a8b7088fd75ad8d7aecda3 Name: appschema Committer: David E. Wheeler <david@justatheory.com> Date: 2016-01-26 15:35:04 -0800 Adds flipr app schema. Deploy 748346dfe73cf2af32a8b7088fd75ad8d7aecda3 Name: appschema Committer: David E. Wheeler <david@justatheory.com> Date: 2016-01-26 14:49:54 -0800 Adds flipr app schema.
  198. History > > sqitch log db:pg:flipr_test On database db:pg:flipr_test Revert

    748346dfe73cf2af32a8b7088fd75ad8d7aecda3 Name: appschema Committer: David E. Wheeler <david@justatheory.com> Date: 2016-01-26 15:35:04 -0800 Adds flipr app schema. Deploy 748346dfe73cf2af32a8b7088fd75ad8d7aecda3 Name: appschema Committer: David E. Wheeler <david@justatheory.com> Date: 2016-01-26 14:49:54 -0800 Adds flipr app schema.
  199. Commit It! >

  200. Commit It! > git add . > git commit -m

    'Add flipr schema.' [master dc23038] 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 dc23038] 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 >
  202. Commit It! > git add . > git commit -m

    'Add flipr schema.' [master dc23038] 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 >
  203. Commit It! > git add . > git commit -m

    'Add flipr schema.' [master dc23038] 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), 943 bytes, done. Total 9 (delta 0), reused 0 (delta 0) To ../flipr-remote a4f765f..dc23038 master -> master
  204. Commit It! > git add . > git commit -m

    'Add flipr schema.' [master dc23038] 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), 943 bytes, done. Total 9 (delta 0), reused 0 (delta 0) To ../flipr-remote a4f765f..dc23038 master -> master
  205. Redeploy >

  206. > sqitch deploy db:pg:flipr_test --verify Deploying changes to db:pg:flipr_test +

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

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

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

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

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

    flipr # Change: 748346dfe73cf2af32a8b7088fd75ad8d7aecda3 # Name: appschema # Deployed: 2016-01-26 15:39:31 -0800 # By: David E. Wheeler <david@justatheory.com> # Nothing to deploy (up-to-date) > Status Update >
  212. Save My Fingers >

  213. Save My Fingers > sqitch config core.target db:pg:flipr_test >

  214. Save My Fingers > sqitch config core.target db:pg:flipr_test > sqitch

    status # On database db:pg:flipr_test # Project: flipr # Change: 748346dfe73cf2af32a8b7088fd75ad8d7aecda3 # Name: appschema # Deployed: 2016-01-26 15:39:31 -0800 # By: David E. Wheeler <david@justatheory.com> # Nothing to deploy (up-to-date) > No URI
  215. Save My Fingers > sqitch config core.target db:pg:flipr_test > sqitch

    status # On database db:pg:flipr_test # Project: flipr # Change: 748346dfe73cf2af32a8b7088fd75ad8d7aecda3 # Name: appschema # Deployed: 2016-01-26 15:39:31 -0800 # By: David E. Wheeler <david@justatheory.com> # Nothing to deploy (up-to-date) > No URI > sqitch config --bool deploy.verify true > sqitch config --bool rebase.verify true > Always verify.
  216. Commit Config >

  217. Commit Config > git add . > git commit -m

    'Add db_name and verify to config.' [master 795697f] Add db_name and verify to config. 1 file changed, 6 insertions(+) >
  218. Commit Config > git add . > git commit -m

    'Add db_name and verify to config.' [master 795697f] Add db_name and verify to config. 1 file changed, 6 insertions(+) >
  219. 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), 376 bytes, done. Total 3 (delta 2), reused 0 (delta 0) To ../flipr-remote dc23038..795697f master -> master > git add . > git commit -m 'Add db_name and verify to config.' [master 795697f] Add db_name and verify to config. 1 file changed, 6 insertions(+) >
  220. Not Migrations? antisocial network

  221. Not Migrations? Incomplete mini-language antisocial network

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

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

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

    difficult to track No SCM 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. SQL Migrations? Incomplete mini-language No logical replication integration Numbered scripts

    hard to track No VCS awareness ——————————————— ——————————————————— Managing procedures is a PITA antisocial network
  229. Sq—what? sql anges ch antisocial network

  230. Sq—what? sq ch antisocial network

  231. it Sq—what? sq ch antisocial network

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

  233. Sqitch Philosophy antisocial network

  234. Sqitch Philosophy No opinions antisocial network

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

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

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

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

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

    dependency resolution Distribution bundling Integrated verification testing No numbering antisocial network
  240. 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
  241. SHAzbat antisocial network

  242. SHAzbat SHA1 ID for every object antisocial network

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

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

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

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

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

    tag, deploy, revert, verify Hashed change text includes: Project Name 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 antisocial network
  249. 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
  250. SHAsome >

  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. >
  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. > Symbolic Sqitch tag
  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. 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. >
  262. SHApay! antisocial network

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

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

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

    any change to the beginning Change tampering (corruption) detectable 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 antisocial network
  267. 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
  268. Sqitch Features antisocial network

  269. Sqitch Features Git-style interface antisocial network

  270. Sqitch Features Git-style interface Reduced duplication antisocial network

  271. Sqitch Features Git-style interface Reduced duplication Built-in configuration antisocial network

  272. Sqitch Features Git-style interface Reduced duplication Built-in configuration Iterative development

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

    Deployment planning antisocial network
  274. Sqitch Features Git-style interface Reduced duplication Built-in configuration Iterative development

    Deployment planning Release tagging antisocial network
  275. antisocial network Your Turn

  276. antisocial network Your Turn Configure Sqitch

  277. antisocial network Your Turn Configure Sqitch Initialize project

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

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

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

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

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

  283. Add Tests > mkdir test >

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

  285. test/appschema. pgTAP Basics

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

    NOT EXISTS pgtap; RESET client_min_messages; BEGIN; -- Plan the tests. SELECT plan(1); SELECT has_schema('nada'); -- Clean up. 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; -- Plan the tests. SELECT plan(1); SELECT has_schema('nada'); -- Clean up. 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; -- Plan the tests. SELECT plan(1); SELECT has_schema('nada'); -- Clean up. 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; -- Plan the tests. SELECT plan(1); SELECT has_schema('nada'); -- Clean up. 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; -- Plan the tests. SELECT plan(1); SELECT has_schema('nada'); -- Clean up. 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; -- Plan the tests. SELECT plan(1); SELECT has_schema('nada'); -- Clean up. SELECT finish(); ROLLBACK;
  292. test/appschema. pgTAP Basics SET client_min_messages TO warning; CREATE EXTENSION IF

    NOT EXISTS pgtap; RESET client_min_messages; BEGIN; -- Plan the tests. SELECT plan(1); SELECT has_schema('nada'); -- Clean up. SELECT finish(); ROLLBACK;
  293. > Run the Test

  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. > 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
  297. First Pass >

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

  299. 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
  300. 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
  301. Pass it On >

  302. git add . > Pass it On >

  303. git add . > git commit -m 'Add appschema test.'

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

    [master e46bdf9] 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), 487 bytes, done. Total 4 (delta 1), reused 0 (delta 0) To ../flipr-remote 795697f..e46bdf9 master -> master >
  305. OMG TAP WTF? The Test Anything Protocol (TAP) is a

    protocol to allow communication between unit tests and a test harness. It allows individual tests (TAP producers) to communicate test results to the testing harness in a language-agnostic way. —Wikipedia
  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 Roles and privileges 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 Roles and privileges 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 Roles and privileges assertions http:/ /pgtap.org/ http:/ /pgxn.org/extension/pgtap/ antisocial network
  354. Other Features and Topics xUnit-Style testing Test-Driven development Integration with

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

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

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

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

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

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

    Run test with pg_prove Make it fail Make it pass!
  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
  362. 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
  363. Let’s talk about… antisocial network antisocial network antisocial network

  364. antisocial network antisocial network

  365. TDD antisocial network antisocial network

  366. None
  367. “The act of writing a unit test is more an

    act of design than of verification. It is also more an act of documentation than of verification. The act of writing a unit test closes a remarkable number of feedback loops, the least of which is the one per– taining to the verification of function.” —Robert C. Martin
  368. antisocial network

  369. TDD is an act of design. antisocial network

  370. antisocial network

  371. TDD is an act of documentation. antisocial network

  372. antisocial network

  373. Okay. antisocial network

  374. antisocial network

  375. But… antisocial network

  376. Database Design antisocial network

  377. Database Design Specify requirements antisocial network

  378. Database Design Specify requirements Implement schema design antisocial network

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

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

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

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

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

    antisocial network
  384. Why TDDD antisocial network

  385. Why TDDD Ensure data quality antisocial network

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

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

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

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

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

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

  392. Why TDDD Identify defects early antisocial network

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

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

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

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

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

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

  399. None
  400. “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?”
  401. None
  402. “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?”
  403. None
  404. “Wouldn’t it be nice to have a test suite to

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

  406. Okay. antisocial network

  407. antisocial network

  408. How? antisocial network

  409. TDD How antisocial network

  410. TDD How Ideally separate from app tests antisocial network

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

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

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

    apps DB should present interface to all Apps may use different permissions antisocial network
  414. 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
  415. 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
  416. Branching Out >

  417. git checkout -b users master Switched to a new branch

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

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

    'users' > Branching Out > > emacs test/users.sql >
  420. test/users.sql Table For One

  421. SET client_min_messages TO warning; CREATE EXTENSION IF NOT EXISTS pgtap;

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

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

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

    RESET client_min_messages; BEGIN; SELECT no_plan(); SET search_path TO flipr,public; SELECT has_table( 'users' ); SELECT finish(); ROLLBACK; test/users.sql Table For One
  425. Run ’Em >

  426. 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 >
  427. 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 >
  428. 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. >
  429. Sqitch Dependencies! >

  430. Sqitch Dependencies! > > sqitch add users --requires appschema \

    -n 'Creates table to track our users.' Created deploy/users.sql Created revert/users.sql Created verify/users.sql Added "users [appschema]" to sqitch.plan >
  431. Sqitch Dependencies! > > sqitch add users --requires appschema \

    -n 'Creates table to track our users.' Created deploy/users.sql Created revert/users.sql Created verify/users.sql Added "users [appschema]" to sqitch.plan >
  432. Sqitch Dependencies! > > sqitch add users --requires appschema \

    -n 'Creates table to track our users.' Created deploy/users.sql Created revert/users.sql Created verify/users.sql Added "users [appschema]" to sqitch.plan > emacs deploy/users.sql >
  433. deploy/users.sq deploy/users.sql -- XXX Add DDLs here. COMMIT; -- Deploy

    flipr:users to pg -- requires: appschema BEGIN; 

  434. deploy/users.sq deploy/users.sql -- XXX Add DDLs here. COMMIT; -- Deploy

    flipr:users to pg -- requires: appschema BEGIN; 

  435. SET client_min_messages = 'warning'; CREATE TABLE flipr.users ( nickname TEXT

    ); deploy/users.sq deploy/users.sql COMMIT; -- Deploy flipr:users to pg -- requires: appschema BEGIN; 

  436. SET client_min_messages = 'warning'; CREATE TABLE flipr.users ( nickname TEXT

    ); deploy/users.sq deploy/users.sql COMMIT; -- Deploy flipr:users to pg -- requires: appschema BEGIN; 
 Bare Minimum
  437. Verily, Users > > sqitch add users --requires appschema \

    -n 'Creates table to track our users.' Created deploy/users.sql Created revert/users.sql Created verify/users.sql Added "users [appschema]" to sqitch.plan > emacs deploy/users.sql >
  438. Verily, Users > > sqitch add users --requires appschema \

    -n 'Creates table to track our users.' Created deploy/users.sql Created revert/users.sql Created verify/users.sql Added "users [appschema]" to sqitch.plan > emacs deploy/users.sql > emacs verify/users.sql
  439. -- Verify flipr:users on pg BEGIN; verify/users.sq verify/users.sql -- XXX

    Add verifications here. ROLLBACK;
  440. -- Verify flipr:users on pg BEGIN; SELECT nickname FROM flipr.users

    WHERE FALSE; verify/users.sq verify/users.sql ROLLBACK;
  441. Unusered > > sqitch add users --requires appschema \ -n

    'Creates table to track our users.' Created deploy/users.sql Created revert/users.sql Created verify/users.sql Added "users [appschema]" to sqitch.plan > emacs deploy/users.sql > emacs verify/users.sql >
  442. Unusered > > sqitch add users --requires appschema \ -n

    'Creates table to track our users.' Created deploy/users.sql Created revert/users.sql Created verify/users.sql Added "users [appschema]" to sqitch.plan > emacs deploy/users.sql > emacs verify/users.sql > > emacs revert/users.sql
  443. revert/users.sq revert/users.sql -- Revert flipr:users from pg BEGIN; COMMIT; --

    XXX Add DDLs here.
  444. revert/users.sq revert/users.sql -- Revert flipr:users from pg BEGIN; COMMIT; DROP

    TABLE flipr.users;
  445. Make Users >

  446. sqitch deploy Deploying changes to db:pg:flipr_test + users .. ok

    > Make Users >
  447. sqitch deploy Deploying changes to db:pg:flipr_test + users .. ok

    > Make Users >
  448. sqitch deploy Deploying changes to db:pg:flipr_test + users .. ok

    > Make Users > psql -d flipr_test -c '\d flipr.users' Table "flipr.users" Column | Type | Modifiers ----------+------+----------- nickname | text | >
  449. sqitch deploy Deploying changes to db:pg: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 db:pg:flipr_test * appschema .. ok * users ...... ok Verify successful >
  450. Make Users >

  451. 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 >
  452. 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 >
  453. 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!
  454. 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 >
  455. SET client_min_messages TO warning; CREATE EXTENSION IF NOT EXISTS pgtap;

    RESET client_min_messages; BEGIN; SELECT no_plan(); SET search_path TO flipr,public; SELECT has_table( 'users' ); test/users.sql Columnist SELECT finish(); ROLLBACK;
  456. SELECT has_column( 'users', 'nickname' ); SELECT has_column( 'users', 'password' );

    SELECT has_column( 'users', 'timestamp' ); SET client_min_messages TO warning; CREATE EXTENSION IF NOT EXISTS pgtap; RESET client_min_messages; BEGIN; SELECT no_plan(); SET search_path TO flipr,public; SELECT has_table( 'users' ); test/users.sql Columnist SELECT finish(); ROLLBACK;
  457. Dead Again >

  458. 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 >
  459. 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.
  460. MOAR Deploy >

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

  462. -- Deploy flipr:users to pg -- requires: appschema BEGIN; SET

    client_min_messages = 'warning'; CREATE TABLE flipr.users ( nickname TEXT deploy/users.sq deploy/users.sql ); COMMIT;
  463. -- Deploy flipr:users to pg -- 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;
  464. > emacs deploy/users.sql > Update Verify >

  465. > emacs deploy/users.sql > Update Verify > emacs verify/users.sql >

  466. -- Verify flipr:users on pg BEGIN; SELECT nickname FROM flipr.users

    WHERE FALSE; COMMIT; verify/users.sq verify/users.sql
  467. -- Verify flipr:users on pg BEGIN; SELECT nickname FROM flipr.users

    WHERE FALSE; COMMIT; , password, timestamp verify/users.sq verify/users.sql
  468. Revert Overhead > emacs deploy/users.sql > emacs verify/users.sql >

  469. Revert Overhead sqitch revert --to @HEAD^ -y Reverting changes to

    appschema from db:pg:flipr_test - users .. ok > > emacs deploy/users.sql > emacs verify/users.sql >
  470. Revert Overhead sqitch revert --to @HEAD^ -y Reverting changes to

    appschema from db:pg:flipr_test - users .. ok > Yes, really. > emacs deploy/users.sql > emacs verify/users.sql >
  471. Revert Overhead sqitch revert --to @HEAD^ -y Reverting changes to

    appschema from db:pg:flipr_test - users .. ok > > emacs deploy/users.sql > emacs verify/users.sql >
  472. Revert Overhead sqitch revert --to @HEAD^ -y Reverting changes to

    appschema from db:pg:flipr_test - users .. ok > Remove > emacs deploy/users.sql > emacs verify/users.sql >
  473. Revert Overhead sqitch revert --to @HEAD^ -y Reverting changes to

    appschema from db:pg:flipr_test - users .. ok > > emacs deploy/users.sql > emacs verify/users.sql > What’s that?
  474. Sqitch Tags antisocial network

  475. Sqitch Tags Start with @ antisocial network

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

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

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

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

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

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

    symbolic tags: @HEAD Last change @ROOT First change Two modifiers: ^ Previous change antisocial network
  482. 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
  483. Specifying Changes antisocial network

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

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

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

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

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

    change users^ Change before users @ROOT~ Second change appschema~ Change after appschema antisocial network
  489. 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
  490. 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 users antisocial network
  491. > sqitch revert --to @HEAD^ -y Reverting changes to appschema

    from db:pg:flipr_test - users .. ok > Whither Users >
  492. > sqitch revert --to @HEAD^ -y Reverting changes to appschema

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

    from db:pg:flipr_test - users .. ok > sqitch status # On database db:pg:flipr_test # Project: flipr # Change: 748346dfe73cf2af32a8b7088fd75ad8d7aecda3 # Name: appschema # Deployed: 2016-01-26 15:39:31 -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". >
  494. Whither Users >

  495. > sqitch verify Verifying db:pg:flipr_test * appschema .. ok Undeployed

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

  497. sqitch deploy Deploying changes to db:pg:flipr_test + users .. ok

    > Back At It >
  498. sqitch deploy Deploying changes to db:pg:flipr_test + users .. ok

    > Back At It > Add
  499. sqitch deploy Deploying changes to db:pg: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 >
  500. sqitch deploy Deploying changes to db:pg: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!
  501. sqitch deploy Deploying changes to db:pg: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
  502. SET search_path = public,tap; BEGIN; SELECT * FROM no_plan(); 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;
  503. SET search_path = public,tap; BEGIN; SELECT * FROM no_plan(); 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;
  504. 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 * FROM no_plan(); 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;
  505. 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 * FROM no_plan(); 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;
  506. 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 * FROM no_plan(); 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;
  507. Columny >

  508. > 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 >
  509. > 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.
  510. User Typography >

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

  512. -- Deploy flipr:users to pg -- 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 , ,
  513. -- Deploy flipr:users to pg -- 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,
  514. -- Deploy flipr:users to pg -- 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,
  515. -- Deploy flipr:users to pg -- 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()
  516. User Typography > emacs deploy/users.sql >

  517. sqitch rebase @HEAD^ -y Reverting changes to appschema from db:pg:flipr_test

    - users .. ok Deploying changes to db:pg:flipr_test + users .. ok > User Typography > emacs deploy/users.sql >
  518. sqitch rebase @HEAD^ -y Reverting changes to appschema from db:pg:flipr_test

    - users .. ok Deploying changes to db:pg:flipr_test + users .. ok > User Typography > emacs deploy/users.sql >
  519. sqitch rebase @HEAD^ -y Reverting changes to appschema from db:pg:flipr_test

    - users .. ok Deploying changes to db:pg:flipr_test + users .. ok > User Typography > emacs deploy/users.sql >
  520. sqitch rebase @HEAD^ -y Reverting changes to appschema from db:pg:flipr_test

    - users .. ok Deploying changes to db:pg: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 >
  521. sqitch rebase @HEAD^ -y Reverting changes to appschema from db:pg:flipr_test

    - users .. ok Deploying changes to db:pg: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.
  522. Additives >

  523. Additives > git add . >

  524. Additives > git add . > git commit -am 'Add

    users table.' [users 610b318] Add users table. 5 files changed, 59 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 >
  525. Pushers >

  526. Pushers > git push --set-upstream origin users Counting objects: 17,

    done. Delta compression using up to 4 threads. Compressing objects: 100% (11/11), done. Writing objects: 100% (11/11), 1.53 KiB, done. Total 11 (delta 1), reused 0 (delta 0) To ../flipr-remote * [new branch] users -> users Branch users set up to track remote branch users from origin. >
  527. Pushers > git push --set-upstream origin users Counting objects: 17,

    done. Delta compression using up to 4 threads. Compressing objects: 100% (11/11), done. Writing objects: 100% (11/11), 1.53 KiB, done. Total 11 (delta 1), reused 0 (delta 0) To ../flipr-remote * [new branch] users -> users Branch users set up to track remote branch users from origin. >
  528. Pushers > git push --set-upstream origin users Counting objects: 17,

    done. Delta compression using up to 4 threads. Compressing objects: 100% (11/11), done. Writing objects: 100% (11/11), 1.53 KiB, done. Total 11 (delta 1), reused 0 (delta 0) To ../flipr-remote * [new branch] users -> users Branch users set up to track remote branch users from origin. >
  529. Wash, Rinse, Repeat antisocial network

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

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

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

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

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

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

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

    change Revise test Revise and rebase change Wash, Rinse, Repeat Commit/Push when done Breathe in, breathe out antisocial network
  537. Caution: Hard Reset Ahead

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

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

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

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

    HEAD snapshot Replaces it with new snapshot Almost un-reversible
  542. 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
  543. 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!
  544. Time to Work! antisocial network

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

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

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

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

    branch -D users git checkout -b users 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 antisocial network
  550. 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
  551. 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
  552. antisocial network Flip Out

  553. antisocial network Flip Out Create flips branch

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

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

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

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

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

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

    flip_id SERIAL PK nickname FK body TEXT timestamptz Use TDDD
  560. 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
  561. Functional Testing >

  562. Functional Testing git checkout -b userfuncs users Switched to a

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

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

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

  566. 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;
  567. 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;
  568. 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; -- Plan the tests. BEGIN; SELECT plan(11);
  569. 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; -- Plan the tests. BEGIN; SELECT plan(11);
  570. test/insert_use SELECT plan(11);

  571. 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' );
  572. 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' );
  573. 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' );
  574. 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' );
  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 test/insert_user.sql 'volatile' );

  577. 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' );
  578. 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' );
  579. 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' );
  580. 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' );
  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 'The user should have been inserted' );

  583. 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' );
  584. 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' );
  585. 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
  586. 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' );
  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 'Both users should be present' );

  589. 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' );
  590. 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' );
  591. 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
  592. 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' );
  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' ); SELECT finish(); ROLLBACK;
  596. Functional Testing emacs test/insert_user.sql > >

  597. Functional Testing emacs test/insert_user.sql > > emacs deploy/insert_user.sql >

  598. deploy/insert_u deploy/insert_user.sql -- Deploy flipr:insert_user to pg -- requires: appschema

    -- requires: users BEGIN; -- XXX Add DDLs here. COMMIT;
  599. deploy/insert_u deploy/insert_user.sql -- Deploy flipr:insert_user to pg -- requires: appschema

    -- requires: users 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;
  600. Functional Testing emacs deploy/insert_user.sql > >

  601. Functional Testing emacs deploy/insert_user.sql > > emacs revert/insert_user.sql >

  602. revert/insert_u revert/insert_user.sql -- Revert flipr:insert_user to pg BEGIN; COMMIT; --

    XXX Add DDLs here.
  603. revert/insert_u revert/insert_user.sql -- Revert flipr:insert_user to pg BEGIN; COMMIT; DROP

    FUNCTION flipr.insert_user(TEXT, TEXT);
  604. Functional Testing emacs revert/insert_user.sql > >

  605. Functional Testing emacs revert/insert_user.sql > > emacs verify/insert_user.sql >

  606. verify/insert_u verify/insert_user.sql -- Verify flipr:insert_user to pg BEGIN; -- XXX

    Add DDLs here. ROLLBACK;
  607. verify/insert_u verify/insert_user.sql -- Verify flipr:insert_user to pg BEGIN; SELECT has_function_privilege(

    'flipr.insert_user(text, text)', 'execute' ); ROLLBACK;
  608. verify/insert_u verify/insert_user.sql -- Verify flipr:insert_user to pg BEGIN; SELECT has_function_privilege(

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

  610. We Good? emacs verify/insert_user.sql > > pg_prove -d flipr_test test/*.sql

    test/appschema.sql .... ok test/insert_user.sql .. 1/11 # Failed test 1: "Function insert_user() should exis # Failed test 2: "Function insert_user(text, text) s # Failed test 3: "Function insert_user(text, text) s # Function insert_user(text, text) does not exis # Failed test 4: "Function insert_user(text, text) s # Function insert_user(text, text) does not exis # Failed test 6: "Insert a user" # died: 42883: function insert_user(unknown, # Failed test 7: "The user should have been inserted # have: NULL # want: (theory,acbd18db4cc2f85cedef654fccc4
  611. We Good? emacs verify/insert_user.sql > > pg_prove -d flipr_test test/*.sql

    test/appschema.sql .... ok test/insert_user.sql .. 1/11 # Failed test 1: "Function insert_user() should exis # Failed test 2: "Function insert_user(text, text) s # Failed test 3: "Function insert_user(text, text) s # Function insert_user(text, text) does not exis # Failed test 4: "Function insert_user(text, text) s # Function insert_user(text, text) does not exis # Failed test 6: "Insert a user" # died: 42883: function insert_user(unknown, # Failed test 7: "The user should have been inserted # have: NULL # want: (theory,acbd18db4cc2f85cedef654fccc4 Yay!
  612. We Good? test/insert_user.sql Failed tests: 1-11 Files=3, Tests=27, 0 wallclock

    secs Result: FAIL >
  613. We Good? test/insert_user.sql Failed tests: 1-11 Files=3, Tests=27, 0 wallclock

    secs Result: FAIL > sqitch deploy Deploying changes to db:pg:flipr_test + insert_user .. ok >
  614. We Good? test/insert_user.sql Failed tests: 1-11 Files=3, Tests=27, 0 wallclock

    secs Result: FAIL > 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 > sqitch deploy Deploying changes to db:pg:flipr_test + insert_user .. ok >
  615. Commitment >

  616. git add . > git commit -m 'Add `insert_user()`.' [userfuncs

    40eabe1] Add `insert_user()`. 6 files changed, 101 insertions(+) create mode 100644 -n 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 >
  617. Push It Real Good… >

  618. git push origin --set-upstream userfuncs Counting objects: 18, done. Delta

    compression using up to 4 threads. Compressing objects: 100% (11/11), done. Writing objects: 100% (12/12), 1.96 KiB, done. Total 12 (delta 1), reused 0 (delta 0) To ../flipr-remote * [new branch] userfuncs -> userfuncs Branch userfuncs set up to track remote branch userfuncs from origin. > Push It Real Good… >
  619. git push origin --set-upstream userfuncs Counting objects: 18, done. Delta

    compression using up to 4 threads. Compressing objects: 100% (11/11), done. Writing objects: 100% (12/12), 1.96 KiB, done. Total 12 (delta 1), reused 0 (delta 0) To ../flipr-remote * [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: 18, done. Delta

    compression using up to 4 threads. Compressing objects: 100% (11/11), done. Writing objects: 100% (12/12), 1.96 KiB, done. Total 12 (delta 1), reused 0 (delta 0) To ../flipr-remote * [new branch] userfuncs -> userfuncs Branch userfuncs set up to track remote branch userfuncs from origin. > Push It Real Good… >
  621. Reset, Mes Amis! antisocial network

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

  623. Reset, Mes Amis! git checkout users git revert -y antisocial

    network
  624. Reset, Mes Amis! git checkout users git revert -y git

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

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

    reset --hard upstream/users git checkout -b userfuncs git reset --hard upstream/insert_user antisocial network
  627. Reset, Mes Amis! git checkout users git revert -y git

    reset --hard upstream/users git checkout -b userfuncs git reset --hard upstream/insert_user git deploy antisocial network
  628. antisocial network None Shall Pass

  629. antisocial network None Shall Pass Create change_pass()

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

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

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

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

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

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

    new_pass Only update if old pass correct Use TDDD
  636. 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
  637. Resets >

  638. > sqitch revert -y > git reset --hard upstream/change_pass HEAD

    is now at 048017a Add `change_pass()`. > Resets > My solution
  639. > sqitch revert -y > git reset --hard upstream/change_pass HEAD

    is now at 048017a Add `change_pass()`. > git checkout master > Resets >
  640. > sqitch revert -y > git reset --hard upstream/change_pass HEAD

    is now at 048017a Add `change_pass()`. > git reset --hard upstream/appschema HEAD is now at e46bdf9 Add appschema test. > git checkout master > Resets >
  641. > sqitch revert -y > git reset --hard upstream/change_pass HEAD

    is now at 048017a Add `change_pass()`. > git reset --hard upstream/appschema HEAD is now at e46bdf9 Add appschema test. > git checkout master > Resets > Known good.
  642. > sqitch revert -y > git reset --hard upstream/change_pass HEAD

    is now at 048017a Add `change_pass()`. > git reset --hard upstream/appschema HEAD is now at e46bdf9 Add appschema test. > git checkout master > Resets > Known good. sqitch deploy
  643. Mergers and Acquisitions >

  644. git merge users Updating d72aeb4..c343b84 Fast-forward deploy/users.sql | 13 +++++++++++++

    revert/users.sql | 7 +++++++ sqitch.plan | 1 + test/users.sql | 29 +++++++++++++++++++++++++++++ verify/users.sql | 9 +++++++++ 5 files changed, 59 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 >
  645. git merge users Updating d72aeb4..c343b84 Fast-forward deploy/users.sql | 13 +++++++++++++

    revert/users.sql | 7 +++++++ sqitch.plan | 1 + test/users.sql | 29 +++++++++++++++++++++++++++++ verify/users.sql | 9 +++++++++ 5 files changed, 59 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…
  646. Mergers and Acquisitions >

  647. > git merge flips Updating c343b84..d6f4ee2 Fast-forward 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 >
  648. > git merge flips Updating c343b84..d6f4ee2 Fast-forward 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…
  649. Mergers and Acquisitions >

  650. > git merge userfuncs Auto-merging sqitch.plan CONFLICT (content): Merge conflict

    in sqitch.plan Automatic merge failed; fix conflicts and then commit the result. > Mergers and Acquisitions >
  651. > git merge userfuncs Auto-merging sqitch.plan CONFLICT (content): Merge conflict

    in sqitch.plan Automatic merge failed; fix conflicts and then commit the result. > Mergers and Acquisitions >
  652. > git merge userfuncs Auto-merging sqitch.plan CONFLICT (content): Merge conflict

    in sqitch.plan Automatic merge failed; fix conflicts and then commit the result. > Mergers and Acquisitions >
  653. > git merge userfuncs 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???
  654. Back in Time… >

  655. Back in Time… git checkout -b userfuncs users Switched to

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

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

  658. Branching Out users branched from master antisocial network

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

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

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

    userfuncs branched from users users and flips merged to master antisocial network
  662. 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
  663. Backbrancher master A

  664. Backbrancher master users A branch

  665. Backbrancher master users A B Add users table branch

  666. Backbrancher master users A B flips branch branch

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  684. sqitch revert -y > git reset --hard HEAD HEAD is

    now at d6f4ee2 Add flips table. > Reset >
  685. sqitch revert -y > git reset --hard HEAD HEAD is

    now at d6f4ee2 Add flips table. > Reset > Use with care!
  686. sqitch revert -y > git reset --hard HEAD HEAD is

    now at d6f4ee2 Add flips table. > Reset >
  687. sqitch revert -y > git reset --hard HEAD HEAD is

    now at d6f4ee2 Add flips table. > Reset > git checkout userfuncs Switched to branch 'userfuncs' >
  688. sqitch revert -y > git reset --hard HEAD HEAD is

    now at d6f4ee2 Add flips table. > Reset > git checkout userfuncs Switched to branch 'userfuncs' > sqitch deploy >
  689. Rebase >

  690. > 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: /Users/david/Desktop/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 >
  691. > 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: /Users/david/Desktop/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.
  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: /Users/david/Desktop/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
  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: /Users/david/Desktop/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…
  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: /Users/david/Desktop/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!
  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: /Users/david/Desktop/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 >
  696. Wha Happen? antisocial network

  697. Wha Happen? Same conflict antisocial network

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

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

    line! antisocial network
  700. Wha Happen? >

  701. > git diff diff --cc sqitch.plan index 16c537f,f6949a6..0000000 --- a/sqitch.plan

    +++ b/sqitch.plan @@@ -4,4 -4,4 +4,8 @@@ appschema 2016-01-26T22:47:50Z David E. Wheeler <d users [appschema] 2016-01-27T00:26:52Z David E. Wh ++<<<<<<< HEAD flips [appschema users] 2016-01-27T00:58:48Z David ++======= + insert_user [users appschema] 2016-01-27T01:02:43Z ++>>>>>>> Add `insert_user()`. > Wha Happen? >
  702. > git diff diff --cc sqitch.plan index 16c537f,f6949a6..0000000 --- a/sqitch.plan

    +++ b/sqitch.plan @@@ -4,4 -4,4 +4,8 @@@ appschema 2016-01-26T22:47:50Z David E. Wheeler <d users [appschema] 2016-01-27T00:26:52Z David E. Wh ++<<<<<<< HEAD flips [appschema users] 2016-01-27T00:58:48Z David ++======= + insert_user [users appschema] 2016-01-27T01:02:43Z ++>>>>>>> Add `insert_user()`. > Wha Happen? >
  703. > git diff diff --cc sqitch.plan index 16c537f,f6949a6..0000000 --- a/sqitch.plan

    +++ b/sqitch.plan @@@ -4,4 -4,4 +4,8 @@@ appschema 2016-01-26T22:47:50Z David E. Wheeler <d users [appschema] 2016-01-27T00:26:52Z David E. Wh ++<<<<<<< HEAD flips [appschema users] 2016-01-27T00:58:48Z David ++======= + insert_user [users appschema] 2016-01-27T01:02:43Z ++>>>>>>> Add `insert_user()`. > Wha Happen? > B
  704. > git diff diff --cc sqitch.plan index 16c537f,f6949a6..0000000 --- a/sqitch.plan

    +++ b/sqitch.plan @@@ -4,4 -4,4 +4,8 @@@ appschema 2016-01-26T22:47:50Z David E. Wheeler <d users [appschema] 2016-01-27T00:26:52Z David E. Wh ++<<<<<<< HEAD flips [appschema users] 2016-01-27T00:58:48Z David ++======= + insert_user [users appschema] 2016-01-27T01:02:43Z ++>>>>>>> Add `insert_user()`. > Wha Happen? > C B
  705. > git diff diff --cc sqitch.plan index 16c537f,f6949a6..0000000 --- a/sqitch.plan

    +++ b/sqitch.plan @@@ -4,4 -4,4 +4,8 @@@ appschema 2016-01-26T22:47:50Z David E. Wheeler <d users [appschema] 2016-01-27T00:26:52Z David E. Wh ++<<<<<<< HEAD flips [appschema users] 2016-01-27T00:58:48Z David ++======= + insert_user [users appschema] 2016-01-27T01:02:43Z ++>>>>>>> Add `insert_user()`. > Wha Happen? > C D B
  706. Scratch that Sqitch antisocial network

  707. Scratch that Sqitch Screwed either way? antisocial network

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

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

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

    Tell it to treat Sqitch plans differently Changes on single lines antisocial network
  711. 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
  712. 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
  713. Re: Union Merge

  714. 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
  715. Hallelunion antisocial network

  716. Hallelunion Just appends lines antisocial network

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

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

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

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

  721. git rebase --abort > Reemerge >

  722. echo sqitch.plan merge=union > .gitattributes > git rebase --abort >

    Reemerge >
  723. echo sqitch.plan merge=union > .gitattributes > git rebase --abort >

    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 > Reemerge >
  724. echo sqitch.plan merge=union > .gitattributes > git rebase --abort >

    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 > Reemerge > Back to B, applies C
  725. echo sqitch.plan merge=union > .gitattributes > git rebase --abort >

    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 > Reemerge > That’s D
  726. echo sqitch.plan merge=union > .gitattributes > git rebase --abort >

    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 > Reemerge > Union merge
  727. echo sqitch.plan merge=union > .gitattributes > git rebase --abort >

    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 > Reemerge > That’s E
  728. echo sqitch.plan merge=union > .gitattributes > git rebase --abort >

    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 > Reemerge > Union merge
  729. echo sqitch.plan merge=union > .gitattributes > git rebase --abort >

    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 > Reemerge > Success!
  730. echo sqitch.plan merge=union > .gitattributes > git rebase --abort >

    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 > Reemerge > emacs sqitch.plan > Success!
  731. sqitch.plan What’s the Plan, Man? %syntax-version=1.0.0 %project=flipr %uri=file://../flipr-remote appschema 2016-01-26T22:47:50Z

    David E. Wheeler <david@justatheory.com> # Adds flipr app schema. users [appschema] 2016-01-27T00:26:52Z David E. Wheeler <david@justatheory.com> # Creates table to track our users. flips [appschema users] 2016-01-27T00:58:48Z David E. Wheeler <david@justatheory.com> # Adds table for storing flips. insert_user [users appschema] 2016-01-27T01:02:43Z David E. Wheeler <david@justatheory.com> # Creates a function to insert a user. change_pass [users appschema] 2016-01-27T01:34:15Z David E. Wheeler <david@justatheory.com> # Creates a function to
  732. sqitch.plan What’s the Plan, Man? %syntax-version=1.0.0 %project=flipr %uri=file://../flipr-remote appschema 2016-01-26T22:47:50Z

    David E. Wheeler <david@justatheory.com> # Adds flipr app schema. users [appschema] 2016-01-27T00:26:52Z David E. Wheeler <david@justatheory.com> # Creates table to track our users. flips [appschema users] 2016-01-27T00:58:48Z David E. Wheeler <david@justatheory.com> # Adds table for storing flips. insert_user [users appschema] 2016-01-27T01:02:43Z David E. Wheeler <david@justatheory.com> # Creates a function to insert a user. change_pass [users appschema] 2016-01-27T01:34:15Z David E. Wheeler <david@justatheory.com> # Creates a function to
  733. sqitch.plan What’s the Plan, Man? %syntax-version=1.0.0 %project=flipr %uri=file://../flipr-remote appschema 2016-01-26T22:47:50Z

    David E. Wheeler <david@justatheory.com> # Adds flipr app schema. users [appschema] 2016-01-27T00:26:52Z David E. Wheeler <david@justatheory.com> # Creates table to track our users. flips [appschema users] 2016-01-27T00:58:48Z David E. Wheeler <david@justatheory.com> # Adds table for storing flips. insert_user [users appschema] 2016-01-27T01:02:43Z David E. Wheeler <david@justatheory.com> # Creates a function to insert a user. change_pass [users appschema] 2016-01-27T01:34:15Z David E. Wheeler <david@justatheory.com> # Creates a function to
  734. sqitch.plan What’s the Plan, Man? %syntax-version=1.0.0 %project=flipr %uri=file://../flipr-remote appschema 2016-01-26T22:47:50Z

    David E. Wheeler <david@justatheory.com> # Adds flipr app schema. users [appschema] 2016-01-27T00:26:52Z David E. Wheeler <david@justatheory.com> # Creates table to track our users. flips [appschema users] 2016-01-27T00:58:48Z David E. Wheeler <david@justatheory.com> # Adds table for storing flips. insert_user [users appschema] 2016-01-27T01:02:43Z David E. Wheeler <david@justatheory.com> # Creates a function to insert a user. change_pass [users appschema] 2016-01-27T01:34:15Z David E. Wheeler <david@justatheory.com> # Creates a function to
  735. sqitch.plan What’s the Plan, Man? %syntax-version=1.0.0 %project=flipr %uri=file://../flipr-remote appschema 2016-01-26T22:47:50Z

    David E. Wheeler <david@justatheory.com> # Adds flipr app schema. users [appschema] 2016-01-27T00:26:52Z David E. Wheeler <david@justatheory.com> # Creates table to track our users. flips [appschema users] 2016-01-27T00:58:48Z David E. Wheeler <david@justatheory.com> # Adds table for storing flips. insert_user [users appschema] 2016-01-27T01:02:43Z David E. Wheeler <david@justatheory.com> # Creates a function to insert a user. change_pass [users appschema] 2016-01-27T01:34:15Z David E. Wheeler <david@justatheory.com> # Creates a function to
  736. sqitch.plan What’s the Plan, Man? %syntax-version=1.0.0 %project=flipr %uri=file://../flipr-remote appschema 2016-01-26T22:47:50Z

    David E. Wheeler <david@justatheory.com> # Adds flipr app schema. users [appschema] 2016-01-27T00:26:52Z David E. Wheeler <david@justatheory.com> # Creates table to track our users. flips [appschema users] 2016-01-27T00:58:48Z David E. Wheeler <david@justatheory.com> # Adds table for storing flips. insert_user [users appschema] 2016-01-27T01:02:43Z David E. Wheeler <david@justatheory.com> # Creates a function to insert a user. change_pass [users appschema] 2016-01-27T01:34:15Z David E. Wheeler <david@justatheory.com> # Creates a function to
  737. sqitch.plan What’s the Plan, Man? %syntax-version=1.0.0 %project=flipr %uri=file://../flipr-remote appschema 2016-01-26T22:47:50Z

    David E. Wheeler <david@justatheory.com> # Adds flipr app schema. users [appschema] 2016-01-27T00:26:52Z David E. Wheeler <david@justatheory.com> # Creates table to track our users. flips [appschema users] 2016-01-27T00:58:48Z David E. Wheeler <david@justatheory.com> # Adds table for storing flips. insert_user [users appschema] 2016-01-27T01:02:43Z David E. Wheeler <david@justatheory.com> # Creates a function to insert a user. change_pass [users appschema] 2016-01-27T01:34:15Z David E. Wheeler <david@justatheory.com> # Creates a function to Perfect
  738. Work It >

  739. > sqitch rebase -y Reverting all changes from db:pg:flipr_test -

    change_pass .. ok - insert_user .. ok - users ........ ok - appschema .... ok Deploying changes to db:pg:flipr_test + appschema .... ok + users ........ ok + flips ........ ok + insert_user .. ok + change_pass .. ok > Work It >
  740. > sqitch rebase -y Reverting all changes from db:pg:flipr_test -

    change_pass .. ok - insert_user .. ok - users ........ ok - appschema .... ok Deploying changes to db:pg:flipr_test + appschema .... ok + users ........ ok + flips ........ ok + insert_user .. ok + change_pass .. ok > Work It > {
  741. > sqitch rebase -y Reverting all changes from db:pg:flipr_test -

    change_pass .. ok - insert_user .. ok - users ........ ok - appschema .... ok Deploying changes to db:pg:flipr_test + appschema .... ok + users ........ ok + flips ........ ok + insert_user .. ok + change_pass .. ok > Work It > { {
  742. > sqitch rebase -y Reverting all changes from db:pg:flipr_test -

    change_pass .. ok - insert_user .. ok - users ........ ok - appschema .... ok Deploying changes to db:pg:flipr_test + appschema .... ok + users ........ ok + flips ........ ok + insert_user .. ok + change_pass .. ok > Work It > { { Awesomsauce
  743. Prove It >

  744. > pg_prove -d flipr_test test/*.sql test/appschema.sql .... ok test/change_pass.sql ..

    ok test/flips.sql ........ ok test/insert_user.sql .. ok test/users.sql ........ ok All tests successful. Files=5, Tests=59, 0 wallclock secs Result: PASS > Prove It >
  745. > pg_prove -d flipr_test test/*.sql test/appschema.sql .... ok test/change_pass.sql ..

    ok test/flips.sql ........ ok test/insert_user.sql .. ok test/users.sql ........ ok All tests successful. Files=5, Tests=59, 0 wallclock secs Result: PASS > Prove It > Booyah.
  746. Make it So >

  747. > git add . > Make it So >

  748. > git add . > git commit -m 'Use union

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

    merge for `sqitch.plan`.' [userfuncs 0e31da9] 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 ../flipr-remote + e7477c...0e31da userfuncs -> userfuncs (forced update > Make it So > Overwrite history
  750. > git add . > git commit -m 'Use union

    merge for `sqitch.plan`.' [userfuncs 0e31da9] 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 ../flipr-remote + e7477c...0e31da userfuncs -> userfuncs (forced update > Make it So >
  751. >

  752. > git checkout - Switched to branch 'master' > >

  753. git merge userfuncs Updating fbf8469..0e31da9 Fast-forward .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 - Switched to branch 'master' > >
  754. git merge userfuncs Updating fbf8469..0e31da9 Fast-forward .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 - Switched to branch 'master' > > \O/
  755. Pusher >

  756. git push Counting objects: 20, done. Delta compression using up

    to 4 threads. Compressing objects: 100% (13/13), done. Writing objects: 100% (14/14), 2.31 KiB, done. Total 14 (delta 2), reused 0 (delta 0) To ../flipr-remote fbf8469..0e31da9 master -> master > Pusher >
  757. antisocial network

  758. Ship it! antisocial network

  759. Ship Shape antisocial network

  760. Ship Shape Good work so far antisocial network

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

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

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

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

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

  766. sqitch tag v1.0.0-r1 -n 'Tag v1.0.0-r1.' Tagged "change_pass" with @v1.0.0-r1

    > You’re It >
  767. sqitch tag v1.0.0-r1 -n 'Tag v1.0.0-r1.' Tagged "change_pass" with @v1.0.0-r1

    > git commit -am 'Tag the database @v1.0.0-r1.' [master 6661268] Tag the database @v1.0.0-r1. 1 file changed, 1 insertion(+) > You’re It >
  768. git tag v1.0.0-r1 -am 'Tag v1.0.0-r1.' > sqitch tag v1.0.0-r1

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

    -n 'Tag v1.0.0-r1.' Tagged "change_pass" with @v1.0.0-r1 > git commit -am 'Tag the database @v1.0.0-r1.' [master 6661268] Tag the database @v1.0.0-r1. 1 file changed, 1 insertion(+) > git push Counting objects: 5, done. Writing objects: 100% (3/3), 346 bytes, done. Total 3 (delta 2), reused 0 (delta 0) To ../flipr-remote 0e31da9..6661268 master -> master > You’re It >
  770. git tag v1.0.0-r1 -am 'Tag v1.0.0-r1.' > sqitch tag v1.0.0-r1

    -n 'Tag v1.0.0-r1.' Tagged "change_pass" with @v1.0.0-r1 > git commit -am 'Tag the database @v1.0.0-r1.' [master 6661268] Tag the database @v1.0.0-r1. 1 file changed, 1 insertion(+) > git push Counting objects: 5, done. Writing objects: 100% (3/3), 346 bytes, done. Total 3 (delta 2), reused 0 (delta 0) To ../flipr-remote 0e31da9..6661268 master -> master > git push --tags To ../flipr-remote * [new tag] v1.0.0-r1 -> v1.0.0-r1 > You’re It >
  771. 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. 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 > {
  774. Bundled? >

  775. > cd flipr-1.0.0-r1 > Bundled? >

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

  777. 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 >
  778. 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 >
  779. 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 > > cd .. > tar czf flipr-1.0.0-r1.tgz flipr-1.0.0-r1 >
  780. antisocial network Merge Madness

  781. antisocial network Merge Madness Merge everything

  782. antisocial network Merge Madness Merge everything Back to master

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

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

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

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

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

    flips userfuncs Union merge sqitch.plan Bundle and ship
  788. 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
  789. Ruh-Roh >

  790. Ruh-Roh sqitch revert -y > git reset --hard upstream/reltag HEAD

    is now at 6661268 Tag the database @v1.0.0-r1. > sqitch deploy > >
  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 sqitch revert -y > git reset --hard upstream/reltag HEAD is now at 6661268 Tag the database @v1.0.0-r1. > sqitch deploy > > Same password
  792. 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 sqitch revert -y > git reset --hard upstream/reltag HEAD is now at 6661268 Tag the database @v1.0.0-r1. > sqitch deploy > >
  793. 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 sqitch revert -y > git reset --hard upstream/reltag HEAD is now at 6661268 Tag the database @v1.0.0-r1. > sqitch deploy > > Not good.
  794. PGCryptonite >

  795. sqitch add pgcrypto -n 'Loads pgcrypto extension.' Adding deploy/pgcrypto.sql Adding

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

    revert/pgcrypto.sql Adding verify/pgcrypto.sql Added "pgcrypto" to sqitch.plan > PGCryptonite > emacs deploy/pgcrypto.sql >
  797. deploy/pgcrypto deploy/pgcrypto.sql -- Deploy flipr:pgcrypto to pg BEGIN; COMMIT; --

    XXX Add DDLs here.
  798. deploy/pgcrypto deploy/pgcrypto.sql -- Deploy flipr:pgcrypto to pg BEGIN; COMMIT; CREATE

    EXTENSION pgcrypto;
  799. sqitch add pgcrypto -n 'Loads pgcrypto extension.' Adding deploy/pgcrypto.sql Adding

    revert/pgcrypto.sql Adding verify/pgcrypto.sql Added "pgcrypto" to sqitch.plan > emacs deploy/pgcrypto.sql > PGCryptonite >
  800. sqitch add pgcrypto -n 'Loads pgcrypto extension.' Adding deploy/pgcrypto.sql Adding

    revert/pgcrypto.sql Adding verify/pgcrypto.sql Added "pgcrypto" to sqitch.plan > emacs deploy/pgcrypto.sql > PGCryptonite > emacs verify/pgcrypto.sql >
  801. -- Verify flipr:pgcrypto on pg BEGIN; verify/pgcrypto verify/pgcrypto.sql -- XXX

    Add verifications here. COMMIT;
  802. -- Verify flipr:pgcrypto on pg 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. -- Verify flipr:pgcrypto on pg 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');
  804. -- Verify flipr:pgcrypto on pg 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');
  805. You Know the Drill antisocial network

  806. You Know the Drill Write revert script antisocial network

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

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

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

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

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

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

  813. > git diff test/insert_user.sql @@ -5,7 +5,7 @@ SET search_path

    TO flipr,public; -- Plan the tests. BEGIN; -SELECT plan(11); +SELECT plan(12); SELECT has_function( 'insert_user' ); SELECT has_function( @@ -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' );
  814. > git diff test/insert_user.sql @@ -5,7 +5,7 @@ SET search_path

    TO flipr,public; -- Plan the tests. BEGIN; -SELECT plan(11); +SELECT plan(12); SELECT has_function( 'insert_user' ); SELECT has_function( @@ -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' );
  815. > git diff test/insert_user.sql @@ -5,7 +5,7 @@ SET search_path

    TO flipr,public; -- Plan the tests. BEGIN; -SELECT plan(11); +SELECT plan(12); SELECT has_function( 'insert_user' ); SELECT has_function( @@ -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' );
  816. 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' -); +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 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' -); +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. 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' -); +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') $$,
  819. 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' -); +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') $$,
  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. @@ -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; >
  822. @@ -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; >
  823. FAIL >

  824. FAIL > pg_prove -d flipr_test test/insert_user.sql test/insert_user.sql .. 1/12 #

    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, 1 wallclock secs Result: FAIL > >
  825. FAIL > pg_prove -d flipr_test test/insert_user.sql test/insert_user.sql .. 1/12 #

    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, 1 wallclock secs Result: FAIL > > As expected.
  826. Back when discussing traditional migration systems, I said… antisocial network

  827. Managing procedures is a PITA! antisocial network

  828. Consider this Change >

  829. Consider this Change git diff 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; >
  830. Consider this Change git diff 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?
  831. Not So Much antisocial network

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

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

    that new file 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 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 antisocial network
  836. 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
  837. 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
  838. >

  839. > 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)); +$$; >
  840. > 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.
  841. Let Sqitch do the work. antisocial network

  842. 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 >
  845. 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 >
  846. 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?
  847. Same Files? >

  848. git status On branch master Changes not staged for commit:

    (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in wor 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 commit deploy/insert_user@v1.0.0-r1.sql revert/insert_user@v1.0.0-r1.sql verify/insert_user@v1.0.0-r1.sql > Same Files? >
  849. git status On branch master Changes not staged for commit:

    (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in wor 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 commit deploy/insert_user@v1.0.0-r1.sql revert/insert_user@v1.0.0-r1.sql verify/insert_user@v1.0.0-r1.sql > Same Files? >
  850. git status On branch master Changes not staged for commit:

    (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in wor 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 commit deploy/insert_user@v1.0.0-r1.sql revert/insert_user@v1.0.0-r1.sql verify/insert_user@v1.0.0-r1.sql > Same Files? > As of @v1.0.0-r1
  851. git status On branch master Changes not staged for commit:

    (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in wor 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 commit deploy/insert_user@v1.0.0-r1.sql revert/insert_user@v1.0.0-r1.sql verify/insert_user@v1.0.0-r1.sql > Same Files? >
  852. git status On branch master Changes not staged for commit:

    (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in wor 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 commit deploy/insert_user@v1.0.0-r1.sql revert/insert_user@v1.0.0-r1.sql verify/insert_user@v1.0.0-r1.sql > Same Files? > Previous deploy becomes revert
  853. What’s the Diff? >

  854. What’s the Diff? diff -u 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; > >
  855. Send it Up! >

  856. Send it Up! > sqitch deploy Deploying changes to db:pg:flipr_test

    + insert_user .. ok > >
  857. > 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 db:pg:flipr_test + 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 | $1$nKO47p03$YRXYTt4NoNncTThLyxzEq1 bar | $1$LbVUs/p.$LVbvPlkD8rJlixW2nS3WP0 (2 rows) > Send it Up! > sqitch deploy Deploying changes to db:pg:flipr_test + insert_user .. ok > > \o/
  859. Can We Go Back? >

  860. Can We Go Back? > sqitch revert --to @HEAD^ -y

    Reverting changes to pgcrypto from db:pg:flipr_test - insert_user .. ok > >
  861. 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 Reverting changes to pgcrypto from db:pg:flipr_test - insert_user .. ok > >
  862. Verify How? >

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

  864. -- Verify flipr:insert_user on pg BEGIN; SELECT has_function_privilege( 'flipr.insert_user(text, text)',

    'execute' ); verify/insert_u verify/insert_user.sql COMMIT;
  865. SELECT 1/COUNT(*) FROM pg_catalog.pg_proc WHERE proname = 'insert_user' AND pg_get_functiondef(oid)

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

    LIKE $$%crypt($2, gen_salt('md5'))%$$; -- Verify flipr:insert_user on pg BEGIN; SELECT has_function_privilege( 'flipr.insert_user(text, text)', 'execute' ); verify/insert_u verify/insert_user.sql COMMIT; Yeah, compare source.
  867. > emacs verify/insert_user.sql > Let’s Go!

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

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

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

    changes to db:pg: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!
  871. Add, Commit, Push, Go >

  872. git add . > git commit -m 'Update insert_user to

    use pgcrypto.' [master 59f5823] Update insert_user to use pgcrypto. 8 files changed, 66 insertions(+), 25 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 >
  873. git add . > git commit -m 'Update insert_user to

    use pgcrypto.' [master 59f5823] Update insert_user to use pgcrypto. 8 files changed, 66 insertions(+), 25 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.75 KiB, done. Total 10 (delta 6), reused 0 (delta 0) To ../flipr-remote 5f4c29a..59f5823 master -> master > >
  874. antisocial network Change It Up

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

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

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

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

    change_pass Use pgcrypo Test first!
  879. antisocial network Change It Up git reset --hard insert_user2 Rework

    change_pass Use pgcrypo Test first! Bundle, tag, release
  880. 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
  881. I’m afraid I have some bad news… antisocial network

  882. None
  883. 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.
  884. I’m afraid it’s true. antisocial network RIP

  885. I’m sorry I have no money left to pay you.

    antisocial network RIP
  886. I hope you enjoyed working here. antisocial network RIP

  887. And that you’re able to use the skills you’ve gained

    in your next job. antisocial network RIP
  888. Git Skillz antisocial network RIP

  889. Git Skillz Branching antisocial network RIP

  890. Git Skillz Branching Diffing antisocial network RIP

  891. Git Skillz Branching Diffing Rebasing antisocial network RIP

  892. Git Skillz Branching Diffing Rebasing Merging antisocial network RIP

  893. Git Skillz Branching Diffing Rebasing Merging Committing antisocial network RIP

  894. Git Skillz Branching Diffing Rebasing Merging Committing Pushing antisocial network

    RIP
  895. MOAR Git antisocial network RIP

  896. MOAR Git Bisecting antisocial network RIP

  897. MOAR Git Bisecting Blaming antisocial network RIP

  898. MOAR Git Bisecting Blaming Pull requests antisocial network RIP

  899. MOAR Git Bisecting Blaming Pull requests Submitting patches antisocial network

    RIP
  900. MOAR Git Bisecting Blaming Pull requests Submitting patches Rewriting history

    antisocial network RIP
  901. MOAR Git Bisecting Blaming Pull requests Submitting patches Rewriting history

    Log formatting antisocial network RIP
  902. MOAR Git Bisecting Blaming Pull requests Submitting patches Rewriting history

    Log formatting git help --all antisocial network RIP
  903. pgTAP Skillz antisocial network RIP

  904. pgTAP Skillz TDDD antisocial network RIP

  905. pgTAP Skillz TDDD Schema testing antisocial network RIP

  906. pgTAP Skillz TDDD Schema testing Scalar testing antisocial network RIP

  907. pgTAP Skillz TDDD Schema testing Scalar testing Functional testing antisocial

    network RIP
  908. pgTAP Skillz TDDD Schema testing Scalar testing Functional testing Relational

    testing antisocial network RIP
  909. MOAR pgTAP antisocial network RIP

  910. MOAR pgTAP Testing privileges antisocial network RIP

  911. MOAR pgTAP Testing privileges Mocking interfaces antisocial network RIP

  912. MOAR pgTAP Testing privileges Mocking interfaces Custom test functions antisocial

    network RIP
  913. MOAR pgTAP Testing privileges Mocking interfaces Custom test functions xUnit-style

    testing antisocial network RIP
  914. MOAR pgTAP Testing privileges Mocking interfaces Custom test functions xUnit-style

    testing Tests maintained in functions antisocial network RIP
  915. MOAR pgTAP Testing privileges Mocking interfaces Custom test functions xUnit-style

    testing Tests maintained in functions http:/ /pgtap.org/documentation.html antisocial network RIP
  916. Sqitch Skillz antisocial network RIP

  917. Sqitch Skillz Adding changes antisocial network RIP

  918. Sqitch Skillz Adding changes Dependency management antisocial network RIP

  919. Sqitch Skillz Adding changes Dependency management Deploying changes antisocial network

    RIP
  920. Sqitch Skillz Adding changes Dependency management Deploying changes Verifying changes

    antisocial network RIP
  921. Sqitch Skillz Adding changes Dependency management Deploying changes Verifying changes

    Reverting changes antisocial network RIP
  922. Sqitch Skillz Adding changes Dependency management Deploying changes Verifying changes

    Reverting changes Rebasing changes antisocial network RIP
  923. Sqitch Skillz Adding changes Dependency management Deploying changes Verifying changes

    Reverting changes Rebasing changes Reworking changes antisocial network RIP
  924. MOAR Sqitch antisocial network RIP

  925. MOAR Sqitch Cross-project dependencies antisocial network RIP

  926. MOAR Sqitch Cross-project dependencies Multiple projects, one database antisocial network

    RIP
  927. MOAR Sqitch Cross-project dependencies Multiple projects, one database Script templating

    antisocial network RIP
  928. MOAR Sqitch Cross-project dependencies Multiple projects, one database Script templating

    Changing Branches antisocial network RIP
  929. MOAR Sqitch Cross-project dependencies Multiple projects, one database Script templating

    Changing Branches Checkout command antisocial network RIP
  930. MOAR Sqitch Cross-project dependencies Multiple projects, one database Script templating

    Changing Branches Checkout command Reverts to last common change antisocial network RIP
  931. MOAR Sqitch Cross-project dependencies Multiple projects, one database Script templating

    Changing Branches Checkout command Reverts to last common change Changes Git branch & Deploys antisocial network RIP
  932. MOAR Sqitch Cross-project dependencies Multiple projects, one database Script templating

    Changing Branches Checkout command Reverts to last common change Changes Git branch & Deploys sqitch help, sqitch help --guide antisocial network RIP
  933. Good luck out there. antisocial network RIP

  934. Agile Database Development 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. David E. Wheeler sqitch.org iovation January 28, 2016