[MUSIC] So let's go on to the next example, so in example four, what we're going to do, is we're going to grow on this concept of having jobs. Now, Travis has a new feature that just gate a little while back ago, and there's a nice blog that talks about the features called stages, and stages basically allow us to organize our jobs into different groupings, so that they're very clear to understand what's happening in each of the different groupings. However, there's some limitations. Like the matrix operations still only work at the top level. So if we want to do, simulate things like what we did here with the matrix operations, we're going to have to work a little harder with stages. However, stages can be very powerful. Remember the after success phase that we added, where we had some complicated logic? Stages allow you to have conditional statements, within the stage itself, that allow us to execute a stage only when we want them. And there's some good documentation that's available on the Travis website on the different conditions. If we open a new browser, I'll just paste in the URL here. It's on the docs.travis-ci.com URL. But the URL where the conditions are listed is /user/condition-v1. And if you look at the different options, we can condition our phases to run on any of these different types of special tokens. We can even expand environment variables to set up different conditions for how we execute our different phases. Now, let's go ahead and start the example by going back to the GitHub desktop. So we'll open the GitHub desktop. And just like before, we're going to build on the branches that we started, so we're going to chose new branch, module2_example3 to build on that branch. And we're going to name this branch module2_example4, we're going to choose the Create Branch option, and let's go work with stages. So like before, we could have used the matrix operation here for environment variables. Now, for Node, there's lot of different versions of Node that we can test with. And docker actually publishes images for Node, for different versions of Node, on Jessie. So let's say we wanted to test our project on Node version eight and Node version ten. Well, I could have an environment variable here called NODE_VERSION=8, where I say, 8-jessie, and I could also have one here for NODE_VERSION=10-jessie. So I'm going to delete these, because we won't need the NPM_TARGET anymore. However, I want to comment this one for right now, and we'll just work on 8-jessie, and then, we'll see what it takes to add a 10-jessie. Now, we're going to make this a little bit more interesting. But remember what I said about I had to cancel the build, because there was some state happening here with the build command? Well, I can remove that, so let's clean this up by no longer building at the top level in the install phase. We're now going to build our docker image completely within the script phase. And we're going to use a couple of different steps for that. And so, the first step is, I want to log into docker now. So I'm going to use the docker login command to log into the docker public registry. And that's where we're going to store a docker image that we're building. In this way, we're going to only build it once for one phase for each different version of node version that we're going to use. So I'm introducing to a new environment variables. One is called $DOCKER_USERNAME, which is the username that I'm going to use to publish the image on docker. And the second is the $DOCKER_PASSWORD. Now, Travis is really cool, it can obfuscate these passwords for me and keep my stuff secure. And so, to do that, what we can do is go back to Travis, and we are going to choose our project. And on the projects page, choose the settings option, and we're going to scroll down here to environment variables. And we're going to inject two new environment variables. The first one is DOCKER_USERNAME, which is what we put in our Yamel file. Now, for me, this is my user account, which is wenlockucd. Now, for you, that'll be your user account, and remember that we had a prerequisite to have a hub.docker.com account, well, this is the chance for you to start using that. Now, we're going to say, display the value in the build log. I'm not going to display that value in the build log, so we're going to, I think if we do that, then, we wont have to worry about that. And in the next one is the DOCKER_PASSWORD. Okay, so now you should have a DOCKER_PASSWORD and a DOCKER_USERNAME. So that means in our build, we can go back to our code, in Atom. And we can rely on these values being in our container when we're building in this phase. Now, the next thing, is to specify a docker built command. And we're going to tag a node image with the word, we're going to use the node version. So this node version, this image name, comes from hub.docker.com. So if we go to Create a new browser tab here, and we go to hub.docker.com, and we sign in with our credentials, And we look for the official image called Node. In the Docker registry, under the Tags section, you'll find different versions of Node that is supported by the official image, and we're simply using one of the official images for that, so we're going to use the docker build -t node and then NODE_VERSION. And then, we're going to use the current Docker file to build our image. Now, at this point, we should have a Docker file that is using this image. Now, it's important that we make some changes here, so that we can actually build the correct docker image with the correct tag. Okay, so this is a nice trick, we're going to use the ARG directive to specify an argument that we're going to pass to our Docker file, and we're going to use the ARG called Docker Image. And the default for it will be the existing from tag, which is on build. We're using node version eight, the on build image. And instead of using the from statement here that we had before, we're going to replace that with a variable here, which is the argument tag. So now, we can specify to our docker file, a particular FROM tag that's specified during the build command, to basically build this docker image. Okay, so let's update our docker image to actually specify the build arg, which is the --build-arg option. And we're updating the NODE_IMAGE. With the particular version of node, which in this case is the node:$NODE_VERSION. So that manes the node image will be passed during the build as node: NODE_VERSION, which will be 8-jessie. And we're going to wrap that in some quotes here, so we're sure that the colon and the dollar sign don't get improperly expanded, the next line will be to see what images we just built. So we use the docker images command to see that. And then, finally, since we have a tagged version of this image now, we can tag it for publishing. So we can use the docker tag command for that. And we'll reuse the tag that we used during the build, and place that there. And then, we will reuse the username at this point. And we'll specify the name of the image as probot-hello. So notice if we're going to use a Docker Repository here called probot-hello, under our username, we better have that repository created on hub.docker.com. Otherwise, things are not going to work like what we expected. So if we choose the Create option, and we go to hub.docker.com, and then, choose Create Repository. We can then choose the probot-hello app, and this is exert example Module 2 Example 4 repo, and we'll choose Create. So now we have a place to push each of our different images into the probot-hello repository on hub.docker.com. So let's go back to our code. And the final step here, is to tag the probot-hello with an appropriate version. So for us, that'll be the the $NODE_VERSION. And we'll include a shaw that we'll get from the current checked out repository. So we use the little git rev-parse command to get that shaw, and use that trick to tag it with a shaw ID, so that it's unique. And then, our final step here, is to push the Docker image that we just built. So if we use the Docker push command, we can then push this final tagged image. So having this final tagged image, on docker means that we can use it in subsequent steps without having built the image for any of the subsequent steps.