<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Blaž Šelih</title>
    <description>The latest articles on Forem by Blaž Šelih (@blazselih).</description>
    <link>https://forem.com/blazselih</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4482%2Fn1174430612_30083010_2604.jpg</url>
      <title>Forem: Blaž Šelih</title>
      <link>https://forem.com/blazselih</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/blazselih"/>
    <language>en</language>
    <item>
      <title>What products or technologies have impressed you?</title>
      <dc:creator>Blaž Šelih</dc:creator>
      <pubDate>Wed, 25 Apr 2018 09:56:48 +0000</pubDate>
      <link>https://forem.com/blazselih/what-products-or-technologies-have-impressed-you-kj8</link>
      <guid>https://forem.com/blazselih/what-products-or-technologies-have-impressed-you-kj8</guid>
      <description>&lt;p&gt;I'm old (by today's developer standards) and have seen a lot of things come and go, pushed by the corporations, hyped by the media and worshiped by the masses :-)&lt;/p&gt;

&lt;p&gt;Basically, I'm not easily impressed and couldn't care less for the next super-duper js library or another reinvention of the wheel. But from time to time something really breathtaking comes along. Here are three things that to this day I still consider mind-blowing.&lt;/p&gt;

&lt;h1&gt;
  
  
  1996, 3dfx Voodoo Graphics
&lt;/h1&gt;

&lt;p&gt;To this day I think there was no bigger single leap in consumer hardware performance than this. It felt like a personal Silicon Graphics workstation on a graphics card.&lt;/p&gt;

&lt;h1&gt;
  
  
  1999, IBM Microdrive
&lt;/h1&gt;

&lt;p&gt;Back in the day, this was like something straight out of the future. Tiny mechanical hard drive with spindle motor, head servo, controller, power electronics etc., all packed into Compact Flash enclosure. I think the miniaturization level is still very impressive today.&lt;/p&gt;

&lt;h1&gt;
  
  
  2009, Google Wave
&lt;/h1&gt;

&lt;p&gt;I feel really sorry that Wave failed so badly. None of the components were really groundbreaking or even that new, but they just fit together in a good way. It was the classic case of the whole being more than the sum of the parts.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Obligatory honorable mention, way before my time
&lt;/h3&gt;

&lt;h1&gt;
  
  
  1958, LISP
&lt;/h1&gt;

&lt;p&gt;Probably the most influential programming language/paradigm/philosophy ever. Need I say more.&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>(Slightly more advanced) deployment with git</title>
      <dc:creator>Blaž Šelih</dc:creator>
      <pubDate>Thu, 29 Mar 2018 13:14:48 +0000</pubDate>
      <link>https://forem.com/blazselih/slightly-more-advanced-deployment-with-git-4ikm</link>
      <guid>https://forem.com/blazselih/slightly-more-advanced-deployment-with-git-4ikm</guid>
      <description>&lt;h1&gt;
  
  
  Deploying can sometimes be a pain and go wrong
&lt;/h1&gt;

&lt;p&gt;As most developers can confirm, deploying and updating a basic web application isn't really rocket science. Transfer the updated files to the server, maybe do some local edits, restart and hope for the best.&lt;br&gt;
This naive approach may be good enough in many cases, but once database structure updates and dependency changes are involved, things can get messy quickly. &lt;br&gt;
Besides, keeping development, testing and production database structure in sync by manually editing and executing a bunch of SQL files is tedious as well as error prone. The same goes for manually managing packages and dependencies. &lt;/p&gt;

&lt;p&gt;Since we should be using a version control system anyway, we'll try to leverage git to perform some of the above tasks.&lt;/p&gt;
&lt;h1&gt;
  
  
  Git (hooks) to the rescue
&lt;/h1&gt;

&lt;p&gt;There is plenty of "Deploy your app using git" articles on the internet. Most of them show how to use the post-receive hook to dump the files from the repository to the project folder and restart the server. &lt;br&gt;
In this post, I will attempt to expand on that and show how to use shell scripts to somewhat automate database and package upgrades. I will also show how to keep a simple deployment log to provide a basic rollback capability. &lt;br&gt;
This is all pretty basic stuff but it is a first step to more complex systems like continuous integration (CI) and delivery (CD) solutions. Hopefully, even this simple setup will make your life as a developer a bit easier.&lt;/p&gt;

&lt;p&gt;As an example, we will be deploying a Python (&lt;a href="http://flask.pocoo.org/"&gt;Flask&lt;/a&gt;) application to WebFaction server. Pip is used to manage the dependencies in the virtual environment and &lt;a href="https://flask-migrate.readthedocs.io/en/latest/"&gt;Flask-Migrate&lt;/a&gt; to handle the &lt;a href="https://www.sqlalchemy.org/"&gt;SQLAlchemy&lt;/a&gt; database migrations. &lt;br&gt;
The application is structured following &lt;a href="https://blog.miguelgrinberg.com/index"&gt;Miguel Grindberg's&lt;/a&gt; excellent &lt;a href="https://www.amazon.com/Flask-Web-Development-Developing-Applications/dp/1449372627/"&gt;Flask Web Developement book&lt;/a&gt; and &lt;a href="https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world"&gt;Flask Mega Tutorial&lt;/a&gt;.&lt;br&gt;
Similar principles should apply no matter the programming language, frameworks and libraries used.&lt;/p&gt;

&lt;p&gt;Some basic familiarity with git and shell scripting is assumed. I will not go into every detail and code fragments are here for illustration only. Examples of pre-receive and post-receive hooks are at the bottom for reference.&lt;/p&gt;
&lt;h1&gt;
  
  
  Local setup and workflow
&lt;/h1&gt;

&lt;p&gt;There is not much to set-up on the client side, except adding a git remote after it was created (see below).&lt;/p&gt;

&lt;p&gt;Once we are done developing and testing the new amazing feature, it is time to deploy it. We will have to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Activate the virtual environment.&lt;/li&gt;
&lt;li&gt;Save the current package configuration into a file by executing &lt;code&gt;pip freeze &amp;gt; requirements.txt&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;Since pip does &lt;a href="https://github.com/pypa/pip/issues/988"&gt;not really do a complete dependency resolution&lt;/a&gt; it is a good idea to verify and, if required, edit the file manually. See &lt;a href="https://pip.pypa.io/en/stable/user_guide/#requirements-files"&gt;pip manual&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Once this is done, add requirements.txt to the repo.&lt;/li&gt;
&lt;li&gt;Add any new database migration files to the repo and commit the changes.&lt;/li&gt;
&lt;li&gt;Push to the remote.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now the server will take over, execute the pre- and post-receive scripts and deploy the app for us.&lt;br&gt;
Happy days!&lt;/p&gt;

&lt;p&gt;All of the above steps can be executed as a shell script as well.&lt;/p&gt;
&lt;h1&gt;
  
  
  Initail remote setup
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;First of all, I would strongly suggest you create identical staging and production environments, except for small non-critical apps. Try out everything in the staging environment before deploying to production.&lt;br&gt;
Also, remote setup will differ slightly depending on your hosting provider but the basics should be the same.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ssh to your server and create a bare git repository (&lt;code&gt;git init --bare&lt;/code&gt;). Set up SSH keys as usual, then add the newly created repo as a remote. Push initial configuration to this remote. &lt;/p&gt;

&lt;p&gt;Checkout the files from the repo to your working directory. It may not be strictly necessary, but I like to keep my working directory and repository in separate folders (bare repo, see above).&lt;/p&gt;

&lt;p&gt;Upload files not included in the version control (security sensitive information) and set the required environment variables.&lt;/p&gt;

&lt;p&gt;Confugure the database, web server, etc. and check that everything works as expected.&lt;/p&gt;

&lt;p&gt;This is now the initial configuration.&lt;/p&gt;
&lt;h1&gt;
  
  
  Deploying using server side hooks
&lt;/h1&gt;

&lt;p&gt;Once the push reaches the server, we will have to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check if the correct branch is being deployed.&lt;/li&gt;
&lt;li&gt;Transfer updated files to the server and update the working directory.&lt;/li&gt;
&lt;li&gt;Install and/or update new packages/dependencies.&lt;/li&gt;
&lt;li&gt;Upgrade the database.&lt;/li&gt;
&lt;li&gt;Finally, log the changes and restart the server.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We will use the &lt;a href="https://git-scm.com/book/gr/v2/Customizing-Git-Git-Hooks"&gt;pre-receive and post-receive hooks&lt;/a&gt; to perform these steps.&lt;/p&gt;
&lt;h3&gt;
  
  
  1) Branch checks
&lt;/h3&gt;

&lt;p&gt;First, we need to make sure that only the correct branch (master) gets deployed. &lt;br&gt;
Both pre- and post- receive hooks receive a list of pushed references on stdin (in the form of old-hash new-hash reference). We can iterate over this information to perform our checks. If pre-receive hook exits non-zero, no pushed references are accepted and deployment will abort this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# pre-receive&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;OLD NEW REF
&lt;span class="k"&gt;do
    if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$REF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ &lt;span class="s1"&gt;'/master'&lt;/span&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then    
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Pushing non-master branch &lt;/span&gt;&lt;span class="nv"&gt;$REF&lt;/span&gt;&lt;span class="s2"&gt;, aborting."&lt;/span&gt;
        &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="k"&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that in this case the repository contains only the 'deployable' master branch and all other branches are rejected. If you wish to store other branches, you can easily integrate above logic into the post-receive hook and not use the pre-receive at all.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) File transfer
&lt;/h3&gt;

&lt;p&gt;Remote repository is updated when push completes. In order to update the working directory, we need to checkout the files from the repository using the post-receive hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# post-receive&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GIT_WORK_TREE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/...        &lt;span class="c"&gt;# working directory&lt;/span&gt;
git checkout &lt;span class="nv"&gt;$NEW&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any local changes are overridden by forcing overwrite (&lt;code&gt;-f&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  3) Packages (virtual environment) update
&lt;/h3&gt;

&lt;p&gt;First we need to determine if any update is required at all. Since we are using pip to manage the packages, we can check if the &lt;em&gt;requirements.txt&lt;/em&gt; file was updated during the push:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; &lt;span class="nv"&gt;$OLD&lt;/span&gt; &lt;span class="nv"&gt;$NEW&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'requirements.txt'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;em&gt;requirements.txt&lt;/em&gt; was changed, we'll activate the virtual environment and run &lt;code&gt;pip install -qr requirements.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;PIP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="k"&gt;if &lt;/span&gt;git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt;  &lt;span class="nv"&gt;$OLD&lt;/span&gt; &lt;span class="nv"&gt;$NEW&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s1"&gt;'requirements.txt'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt; /home/.../venv/bin/activate
    pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-qr&lt;/span&gt; requirements.txt
    &lt;span class="nv"&gt;PIP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Option -q will suppress a rather verbose pip output, but will still show the errors. Variable PIP is used later for logging (see bellow).&lt;/p&gt;

&lt;h3&gt;
  
  
  4) Database upgrade
&lt;/h3&gt;

&lt;p&gt;Database migration files are stored in &lt;em&gt;app/migrations/versions&lt;/em&gt;, so we can use the same git diff trick to detect any changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt;  &lt;span class="nv"&gt;$OLD&lt;/span&gt; &lt;span class="nv"&gt;$NEW&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'app/migrations/versions'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, we'll need to activate the virtual environment and then execute the manager.py to upgrade the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="k"&gt;if &lt;/span&gt;git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; &lt;span class="nv"&gt;$OLD&lt;/span&gt; &lt;span class="nv"&gt;$NEW&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s1"&gt;'app/migrations/versions'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt; /home/.../venv/bin/activate
    python manager.py db upgrade
&lt;span class="nv"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5) Log changes and restart the server
&lt;/h3&gt;

&lt;p&gt;We will use the current time, author, old git hash, new git hash as well as packages and database update status to generate a simple CSV log file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;AUTHOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;git show &lt;span class="nv"&gt;$NEW&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"%an"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nv"&gt;TIME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-Is&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TIME&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$AUTHOR&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$OLD&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$NEW&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$PIP&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; updates.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, restarting the server should be fairly self explanatory.&lt;/p&gt;

&lt;p&gt;If everything worked as planned the updated application should now be running.&lt;/p&gt;

&lt;h1&gt;
  
  
  Rollback
&lt;/h1&gt;

&lt;p&gt;First, note that sometimes complete rollback is not even possible, because data may be lost while downgrading the database. It is usually easier to deploy a small fix, than doing the complete rollback.&lt;/p&gt;

&lt;p&gt;In case you still need to revert to the older version, you can use the information from the log, repository and local environment to get things back into working order.&lt;/p&gt;

&lt;p&gt;This is best done by manually reversing the steps from deployment:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Try to figure out what went wrong (by far the most important step)!&lt;/li&gt;
&lt;li&gt;Activate the virtual environment.&lt;/li&gt;
&lt;li&gt;Consult the log and verify if database was upgraded. Execute &lt;code&gt;manage.py db downgrade&lt;/code&gt; if required. This will downgrade the database structure to previous version. You may lose some data during this step!&lt;/li&gt;
&lt;li&gt;Checkout old files from the repository, forcing overwrite.&lt;/li&gt;
&lt;li&gt;Check if the packages were upgraded and, if required, downgrade them by executing &lt;code&gt;pip install -r requirements.txt&lt;/code&gt;. Fortunately, most packages are backward compatible and this step is usually not needed.&lt;/li&gt;
&lt;li&gt;Restart the server and hope for the best.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Examples
&lt;/h1&gt;

&lt;h3&gt;
  
  
  pre-receive
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# pre-receive&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;OLD NEW REF
&lt;span class="k"&gt;do
    if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$REF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ &lt;span class="s1"&gt;'/master'&lt;/span&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then    
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Pushing non-master branch &lt;/span&gt;&lt;span class="nv"&gt;$REF&lt;/span&gt;&lt;span class="s2"&gt;, aborting."&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="k"&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  post-receive
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# post-receive&lt;/span&gt;

&lt;span class="nv"&gt;ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/.../app-folder
&lt;span class="nv"&gt;VENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/.../virtual-environment-folder
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GIT_WORK_TREE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$ROOT&lt;/span&gt;
&lt;span class="nv"&gt;PIP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="nv"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

&lt;span class="nb"&gt;read &lt;/span&gt;OLD NEW REF        &lt;span class="c"&gt;# only master was accepted, no need to iterate&lt;/span&gt;

git checkout &lt;span class="nv"&gt;$NEW&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; &lt;span class="nv"&gt;$OLD&lt;/span&gt; &lt;span class="nv"&gt;$NEW&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s1"&gt;'requirements.txt'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="nv"&gt;$PIP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
    &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="nv"&gt;$VENV&lt;/span&gt;/bin/activate
    pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-qr&lt;/span&gt; &lt;span class="nv"&gt;$ROOT&lt;/span&gt;/requirements.txt
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Packages upgraded"&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"No package changes detected"&lt;/span&gt;
&lt;span class="k"&gt;fi

if &lt;/span&gt;git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; &lt;span class="nv"&gt;$OLD&lt;/span&gt; &lt;span class="nv"&gt;$NEW&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s1"&gt;'app/migrations/versions'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
    &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="nv"&gt;$VENV&lt;/span&gt;/bin/activate
    python3 &lt;span class="nv"&gt;$ROOT&lt;/span&gt;/manage.py db upgrade
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Database upgraded"&lt;/span&gt;
&lt;span class="k"&gt;else
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"No database change detected"&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;AUTHOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;git show &lt;span class="nv"&gt;$NEW&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"%an"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nv"&gt;TIME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-Is&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TIME&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$AUTHOR&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$OLD&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$NEW&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$PIP&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$ROOT&lt;/span&gt;/updates.log

&lt;span class="nv"&gt;$ROOT&lt;/span&gt;/apache2/bin/restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>git</category>
      <category>python</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
