• Servers and Tools

Making a Fancier Deploy Script

From the class:  Git Deploy

One of the reasons that I'm doing this by hand is to give you a sense of what's possible. And as you watch these videos, you should be thinking to yourself, how could I customize this to do what it is that I need it to do. And I'm hoping that I am able to give you these tools that you can use to do that from scratch. So instead of having to rely on a framework that does every single thing for you, you can know how it's all working under the hood and make it do exactly what you need it to do.

So what I'm going to do with this script, I'd like to make a few updates to it. And this was nice as a simple one. But I'm going to go ahead and paste in one that does quite a bit more. And I'm going to walk you through it. Instead of having you to watch me type it all in, I'm just going to show you what it's doing.

First I'm going to print out deployment started with this nice green color. So that's what this slash e is doing with the 32. You can look at colors and Bash and see how this works. But this will print this out in green so it's easier to see. Added some comments about what each of these lines are doing.

And then I'm going to allow other scripts to be executed later on. And so what I'm going to do is go ahead and source the profile, if one exists, in /etc/profile. So this way our path environment variable will be set, and thing we can find executables in different locations.

So if there's a profile set here, we'll go ahead and export that, or grab the path and export it into the environment. And then moving down a little bit further, it's the same line here that we had before. We'll read in from standard input, except I'm just going to double check once we've done that that the new revision is not null.

So what this is checking for is, it's saying, if this value here is null-- that's what this dash z means-- and this weird syntax here is saying, by default set it it to null. So if this is an empty string, set it to the null byte here. If that's true, then just exit out because it means that we pushed up a reference that doesn't exist or that we pushed up a reference that is a delete instead of actually updating. So if that's the case, we just err out, because there's nothing we can do.

And then down here, we're going to use something called umask, which you can do some research on your own time. But what this does, in short, is it says that any files that are written from here on in, we're going to make sure that they're not writeable for world userrs. So in the other users group, they're not going to write or have the write permission set for everyone.

All right. And then we're going to check out the refname, just like we were doing before. And I added a little bit of code here to log what's happening to a log file. So we're going to log out to the log directory that we created in the beginning of the class in a log file called deploy.log. And I'll go ahead and make sure that this exists and that the log file exists, give it the right permissions.

Making the directory executable so we can change into it and the log file will be readable and writeable by the user in the group, and only readable by everybody else. The down here, we're going to be a little bit smarter this time. Instead of just doing the same thing every time, first I'm going to check whether or not this is the first time that we're deploying. And we can tell that if the old revision is null. So if the older version is null, we'll assume this is the first time that we're deploying.

We'll go ahead and initialize all the sub modules. We haven't covered sub modules yet, but you can have sub get projects inside of a Get project. And those become sub modules. So we'll go ahead and update those. And we're going to pipe any kind of output into this program called T. And T, as you might expect, means that we're going to take something as input to it and then send it into two different locations.

So usually you're sending it to standard out, so that's going to be the console, and then also to a file. And so this is going to print it to standard out and append to the log file. So that's what the T program does.

Then, down here on this line, this is going to check whether or not this file exists in our project. So config set up. And this is where we're going to get a little bit fancier than last time. What I want to do is just have this script here be sort of a generic script, one that can work with any project.

And instead of putting the restart Boom service of code inside of this, I'm going to call into a hool-- we'll just call this a hook. This is going to be our own hook this time, though, that's in our project. So if this file inside of config, the setup file, if that exists, that's what this x does, if that exist then this is going to be true. And the next part of this statement will get executed.

So it'll say, if this exists then go ahead and execute that script. And we're going to pass to it as arguments the old revision and the new revision. And we're going to send standard output and standard err to the T program, which will append it to the log file and send it to standard out. So we see it in the console.

Now, if it's not the first time we've deployed, then we'll go ahead and echo out the date to the log file. And then write out the files that have changed just like last time, except this time notice we're piping that output into T so that goes into the log file. Update the sub modules, and then, if there's a deploy script inside of our config directory, go ahead and execute that file again, passing the old revision and the new revision.

Then finally, down at the very bottom, we're just echoing out that the deployment has completed. Again, doing it in green so it's easy to see. So now this way we can kind of change what the deploy script does depending upon the application. And so we'll call into a very specific deploy script inside of our config directory in our app. Let's go take a look at that file.

I created this off camera and I made it executable. And it just needs to be under the config directory, and it needs to be executable. You notice there's no set up script here because I decided I don't need a set up script. I just want the deploy one.

And we're going to say it's a Bash script. It could be a Node script or a Ruby script or any other interpreter we want to use. And in this case, it's very simple. It's just going to echo out that it's restarting the app service, and then pseudo system control restart Boom. You could imagine we could put all kinds of stuff in here. We could, for example, run a bundle process if you're on Rails. Or if you're in Meteor, you can run the build process here. So usually there'll be some kind of build step or bundling step. And then you would restart the services.

Or you can imagine if you had a central deployment server, you might manage the deployment in one place, bundle it all up, and then sends the bundled application to a bunch of different servers. So there's all kinds of different ways that we can hook into this in a sophisticated way. But I'm going to make it quite simple here. And all it's going to do is restart the server.

All right, let's get these the latest scripts up to the server and try this out. I'll start off by secure copying the updated post receive hook and sending that up to post receive. And let's commit some changes here, and try pushing to the server. Get push deploy master.

All right. This is looking pretty slick. We get, in green text, deployment has started. It's much easier to pull it down and see it here. And it tells us all the different things that have happened. We've changed one file. And then this, restarting the app service, happens inside of our custom hook inside of the app. That's the deploy file that you saw earlier, deploy. And then when it's all done, it says deployment completed.

So this is a pretty sophisticated completely working deploy system that has been plugged in to Get. And I hope that gives you some good ideas about how you can build your own deployment system, or to understand better how one of the other tools that you're using to do deployments actually works under the hood.

Now there's a bunch of other tools that we use to help us provision automatically and do some of this stuff automatically. But I wanted to do everything by hand because you ought to see how it all works. And it will give you more tools in your head to be able to solve a more diverse set of problems throughout different projects that you're on.

So I wanted to really start this off by hand and later on we'll add tools to this tool set to automate these different tasks so we don't have to do them again and again. But I hope this class gave you some ideas.

Two more quick things. A lot of the ideas that I got for this class and for that Get deploy script came from this project called Get Dash Deploy from this guy. He works at GitHub. And I highly recommend you go to this GitHub page and you clone this repository and take a look at its source. It'll give you a lot of cool ideas.

And that's one of the great things about knowing Get. You can go and take a look at other people's source code and learn from it. And lastly, if you enjoyed this class, I'd appreciate it if you go out to Twitter or Facebook or any of the social media sites and let your friends know about it. Help me spread the word.