 Today's Visual Studio Toolbox, Aaron is going to give us a quick overview of GitHub actions, which are new and they're an interesting way of doing CI-CD pipelines from within GitHub. Hi, welcome to Visual Studio Toolbox. I'm your host Robert Green and joining me today is Aaron Powell. Hey, Aaron. Howdy, thanks for having me. Thanks for coming back on the show. Today, we're going to talk about GitHub actions. That's right. This is cool. This is a new thing recently introduced and something that I've wanted to do an episode on for a while, so this is great. Well, I'm glad that I'm the perfect candidate to show you just how to get started with it. So let's review at the highest level. What is a GitHub action? So GitHub actions is a CI-CD process or continuous integration continuous delivery platform similar to you might have used with Azure Pipelines or other third parties such as Travis CI or Jenkins and things like that. But this one is built directly into GitHub, so that if you're working with GitHub already as part of your toolbox, we don't need to include another third party product, whether it's Azure Pipelines or something else, to do that CI-CD process that we want. So this is in line with the previous episode where we said that inside Visual Studio Code you can do your source control, you can publish to Azure without having to change context and from all in your work environment. So this is similar. You've got your code in GitHub. You could certainly go over to Azure DevOps and set up your CI-CD Pipeline, but now you're bouncing from there over to GitHub. GitHub actions give the ability to do similar things in one place. Exactly. Cool. There's also some events. Yeah. Yeah. There's another advanced stuff that we could do such as tying into other events that might happen in GitHub. So if someone's raising an issue or working with pull requests, we can trigger off different things to happen, not just deploy straight through to production every time someone raises a bug. I don't want to do that. Okay. Cool. Let's see. Yeah. So to get started, we'll see there's a new tab that's appearing in our GitHub application. So this application is the same one you built on the previous episode. We'll have a link to that on the show notes that people want to drill down into the awesome trivia API app. Exactly. If we click on this, we'll get presented with a bunch of starter templates that we've got for GitHub actions. You see if they're doing like Node.js application. So is actions always there or do you have to turn it on somehow? So actions, it'll always be there on projects that you create. Okay. It's a feature that's recently gone through the preview cycle. So some accounts might not have it activated just yet. Okay. But it's rolling out pretty much to everyone as we're speaking. Okay. Got it. Yeah. We can say a whole bunch of starter templates. There's similar as we find in a lot of other platforms. Things that we've got that are popular. We're just building like a Node.js application, or we're trying to build a package that we're publishing to the Node package repository. But then we've got integrations with Azure Web Apps, or maybe we're building a Python application. A whole bunch of different things that we might be doing in here. Okay. Let's just have a quick look at maybe one of these. We'll grab the deploy a web app to Azure. You can see that this is what we've got as a starting point. It's created a place where a file will go in our GitHub repo. It's at .github as a folder, slash workflows and then the name of the workflow that we want to run. So a workflow is what we call a GitHub Action series of steps. So it's kind of similar to, and I want to spend the whole episode doing side by side, but this is kind of similar to Azure DevOps. You're building a YAML pipeline. Yep. The pipeline is a set of actions or tasks that take place. Yep. You've got a list of them on the right and you've got the YAML on the left. Correct. Yeah. So we've got the ones on the right-hand side, the ones out of the marketplace that we could select and add in just like you would do with Azure DevOps. There is our YAML file that would be created to this. Now, if I was going to use this one, I would then just hit Save and Commit up here, and that will put it into my Git repo. But I want to show you how we can build one from scratch. So we can understand a bit more about what's happening and the pieces that make up to GitHub Actions file. I'm going to just hit Cancel here and we'll drop back, and I'm going to jump over to Visual Studio Code. Now that we're in Visual Studio Code, let's create our YAML file like the starting point. So I'm going to do that by creating a new file, and here's a nifty little trick that I learnt recently with Visual Studio Code is that if I want to create a file in a particular folder, I can actually include that folder path while creating the file. So I can do .github slash workflows. Nice. I did not know that. We'll just call this devops.yml. It does support YML or I just prefer one less character. We'll pop that there and we can see here in the sidebar, it's created that folder automatically just because I put in the path. I think that's a nifty little trick that it took me a long time to learn that that existed. Now with a workflow, we need to create a bunch of metadata around it, similar that we would have with other YAML-based ones such as a name and what's going to make that trigger and things like that. I'm going to copy and paste some code so we don't have to watch me type it all out, and we can talk about what's happening as we're doing that. So here's one I've created earlier. We'll just grab the starting bit of it. So we're going to name. The YAML you're using here is pretty similar to the YAML that you'd use in Azure DevOps more or less. There's definitely some overlaps with it. There's some GitHub nuances to it because of the slightly different approach to the way the actions work relative to the way tasks work in Azure DevOps. You could use it as a good starting point. Yeah. If you're familiar with doing the YAML pipelines within Azure Pipelines, you'll see similarities and be like, okay, I understand some of the terminology and the concepts that we bring across. Okay. Cool. So we've got a name and things that will appear, because we can have multiple of these. We might have some that are only happening on pull requests, so that might be just doing like a test and not actually deploying anything, and this is the one that's going to deploy all the way through our production. So we can name them differently. It just makes it easy when we look at it with inside of the GitHub website. Then we need to specify an event that this action is going to trigger on. So I'm going to say that this is going to trigger on pushes to a branch named master. Right. If I had multiple branches, I could specify multiple different branches. Yes. I can specify ignore branches as well. So if I had a branch that I didn't want to get built using this particular pipeline, sorry, this particular workflow, I can do it. Now with that done, we need to start setting up the things that are going to actually happen. Because this is useful, but it's not going to do anything yet. It's like it will trigger but doesn't do anything. This says do something, now the question is what am I doing? Exactly. So I'll go grab some more of the stuff back from the one that I've written earlier. We'll just copy it all across, and we'll talk about it as we go through. Our first thing is that I've got jobs. Jobs are the things that I'm going to run. Inside of this, I can have multiple different jobs that can either be run in sequence or in parallel. In this case, I've only got one job, it's called build. But if I had maybe a test and I want to do deployments separately, or maybe I had unit tests and integration tests, I get a job named tests, and job named integration tests, and job named deployment. But I just want to keep it simple for this little example that we're looking at. You can name your jobs by that first level indent here, we see on line nine where it says build. Now, you can name that whatever I want. I just use build because it helps me know what it's for. Then we need to specify what kind of agent that this is going to run on, or what is the host for this. Now, we can use Windows, Linux, or Mac, because we're building a Node.js set of Azure functions. I'm just going to use the Ubuntu latest agent, so a Linux agent. But if you think about building an application you might want to run tests against multiple different ones. You could build on Linux and on Windows and on Mac all from the same pipeline just by changing the runs on section of our GitHub Action. Finally, we have steps. What are we actually doing in this action? Well, sorry, what actions are we actually going to do in this workflow? Now, we'll see each of these steps have a name. The first one here, check out. So that's going to get our code out of our Git repo. Then we specify a users. This is to use the Azure Pipelines analogy, the task that we're going to run at this step. So this check out action is going to use an action that's been predefined called check out. The syntax for this is a little bit different to what we have used if we've been doing it with GitHub Action. Sorry, with Azure Pipelines. I've got so many DevOps tools that I'm working with, that it all blows into one sometimes. Here we actually specify a GitHub repo or a moniker to a GitHub repo that is what's existing in our marketplace. So there's actually a repo if we go github.com.actions.checkout, and that's what we're using here. Then with that, we can specify what tag or branch or even the char that we want to use for that particular action to run at this point in time. It's recommended that we don't just say at latest or at master or something like that, because every time someone pushes an update to that action, you're going to immediately use it without necessarily realizing it. So we want to use something like a tagged version or maybe a char just so that we have confidence that our builds are repeatable based off of something that we know has been pinned previously. But we also don't need to use a check out action. If we had somewhere like our deploy to production environment, we're probably not needing the source code for that. We might be just downloading assets. So we can also drop some of these as we don't need them. Okay. The next one, because this is a Node.js set of Azure Functions, I need to install Node on the machine. Right. To do that, I grab a different action. This one is set up Node because I don't know what version of Node I might want or I don't know what one the action would want to be used by the fault. We can provide parameters to it. We do that with the with part of the YAML statement, and then we can pass parameters. So Node-version is the version of Node to use here, and then I'm just doing 12.x. Does that impede repeatability though? Because you now know that every time you run this, you might get a different version of Node. What's the trade-off between specifying it and leaving it open-ended like this? Well, so because I want to specify that, I want to ensure that repeatability. It's always going to use the same version of Node. But if maybe I was doing something that was, I was less concerned about the underlying host changes, I wouldn't necessarily need to provide that, and we'll just pick the latest forms. I would always encourage people to specify exact versions whether it's .NET, Python, Java, etc. Because as you said, you want repeatability. We don't want, oh, it worked last week. That's one of the promises of the DevOps practices is repeatability. Exactly. We can even parameterize the way that this all works. So that we might have a global environment variable that says this is the Node version to run for the pipeline, and stuff like that. Although maybe repeatability, there's also predictability because you don't necessarily know when you deploy this. If you're deploying it to something that has a latest version, then this would catch that. So it's kind of a trade-off. Yeah, exactly. All right. Then we're doing MPM install. So we can just run a script. It's just like a pass script or if I was on Windows, we can specify a PowerShell script, or if we're using cross-platform PowerShell, we could even do that in here. But then we pull in appropriate action. It's got a couple of built-in things. It's got a built-in shell that it can run. So we just do like an MPM install, and then the thing that we really want to do is deploy our code somewhere. Yes. That's where we're going to start working with Azure. So this workload is doing the build and the deploy in one. This is just one single step. So if any of these steps fail, it won't continue on like it might not deploy Azure. But I'm kind of used to over in Azure DevOps building my CI pipeline, and then my CD pipeline. This is just one workload that does both. Just in this example. I could definitely split them out if I wanted to. So I could have completely separate workflows and trigger a release workflow after the build had completed, or I could even have them with inside of the same workflow file and to where I've got like the build node specified on line nine, I could also specify another node somewhere which is release and have that dependent on the successful completion of build. And then we use assets to pass around outputs from builds and stuff like that. So we can still do all that same sort of thing here. It's just to what level of complexity you want because it will all happen through the same series of GitHub actions. Right. So yeah, to log into Azure, we use the Azure action. So there's one existing. So we go github.com. Azure slash login, that's our action. And we can see the source code for that there as well. But we're going to need some credentials, right? Well, presumably. Well, hopefully our GitHub can't just go, oh, I'm just going to deploy to a random place with inside of Azure. I don't need any security for that. That doesn't sound like the best way to go about things. Nope, you have to supply that. Yeah. And we probably don't want to put our credentials directly with inside of this file because it's going into our repo. Right. So for that, we can use secret variables that are defined against our GitHub project. So I've already done that because I didn't want to publish my credentials to everyone but I'll just show you how you would do that if you were doing it for a project yourself. So we're going to jump back to our browser and we'll come to the settings of our GitHub project. And then we'll scroll down to secrets in the menu here. And you'll see I've got one in there called Azure credentials. So you store those in GitHub and then it just reads from there. Yeah, so like you would have variables and secret variables inside an Azure pipeline. We can have those here as well. So I can hit add a new secret, give it a name, give it a value and that will appear in there. And then that is made available to actions when they're run using this dollars and double squiggly brackets. And is that stored at the repo level, at your account level? It's stored at the repo level. So if you've got multiple GitHub repos, you can have different secrets across each of them. And if for some reason why one of them got compromised you could have just those credentials recycled. And it doesn't mean that you've given access to everything, all the keys to the castle. Yes, okay, cool. And the very last one that we've got here is that we are going to deploy our Azure function. So again, we're grabbing our action and we're probably familiar with this through by now in GitHub repo. I've pinned it, this and the login, I've pinned both at V1. So it's a tag that someone has put on the GitHub repo and the code in there. So I'm confident that that's where that will be. And I have to provide it with a bit of information which is the name of the Azure function that I want to deploy to. So I've already created my Azure function here. And if I just hit refresh, we'll see that I haven't got anything deployed to that. And now let's commit this GitHub action into our repository and push it up. And fingers crossed, we're going to deploy our trivia app straight from a Git push. And do you need to specify a trigger that this automatically runs on check-in or is that automatic? So that's what we've done at the very top of this file where we've got the on. So that's the event. So the on. Yeah, so that's our trigger. So that's your trigger, got it. Yeah, there's a lot of different triggers and we'll put the documentation for GitHub actions in the show notes because there are a lot of different events that we could also tie into. Things that are happening around your repository that are not just related to source code that you might want to perform GitHub actions against. And then you could specify that it's not automatically triggered, right? It's just manual. Okay, cool. All right, so we'll commit this in adding GitHub actions. I love the fact that being familiar with how pipelines work in Azure DevOps, you now know a giant chunk of what you need to know to come over here and use these. Exactly. That's pretty cool. Presumably vice versa. Exactly. It means that if, as a company, you've started using GitHub a bit more and more and you want to try out these tools that are built in, you don't want to have to jump back and forth. Or you wind up your weekend job, you're working with a buddy who's got some code and he says, oh, I got GitHub actions going on here. He's like, okay, well, I already know a lot about how this works so you can just kind of slide in and learn some new stuff. Cool. So I'm just pushing up those changes to GitHub. We'll give that a minute while the magic of the internet works and the files all fly up there. And it said that it just wants me to also do a get fetch to make sure that I've got all updates from the remote repository as well. Because I had been doing some work on another machine. Now, we come back over here, hit GitHub actions. Okay, so build and deploy. That was the name that we had in our YAML file and we'll see that it's already happened and it was triggered on a push. Now, one thing that is different to a lot of other deployment tools that I've worked with is that this is related to that commit. So it's very easy to work out which commit triggered it. So I can go back and go, ah, no, if I did have something fail, I can have a look back and go exactly the point in time. There it was and it's all linked all straight from the GitHub UI. I can easily jump to things. So we can see there's the commit ID appearing with inside of the browser. I can click through and I can see, ah, that was the change that happened that triggered this particular pipeline. There's a whole history, et cetera. And you can figure out how many check-ins broke the build and all that. Now, if I jump over here, so in the right hand, sorry, the left hand side, it's my left hand, yes. It's everyone's left hand. We can see the name of that job that we had executing, which is the build job. And because this has already been running for a few minutes while we're talking, we'll see that the steps have already happened. There's a whole bunch of green checks. I mean, we can expand some of these and say, set up node. Yeah, it's just again, I think you look at the first couple of times, you know, you see that it's doing all the things you'd expected to do and then you stop staring at it. Yeah, okay, it's given us all green checks. So it means that everything must have been successful. And yeah, our pipeline has all run completely. So if we jump back over to Azure, we'll give our functions a refresh. And now it's checking because we should have actually deployed up the functions. We'll give it a moment. Fingers crossed, like I said, because it's the first time we've done deployment and my experience has always told me that the first time you push a new deployment file and a new deployment pipeline, it will never work immediately. You're always recovering, so I'm optimistic. Yeah, it's always like. You have to be, you have to notice next to functions, the spinning arrows, which tells you that it's not done yet. Yeah, that's what we're waiting for. Right. Maybe we'll give it another refresh. Hopefully it hasn't timed out. Excellent, there we go. There we go. So there's our functions. They got all deployed up because we didn't have anything there before. We can come into here, we can grab the URL and get the response. It's just the same as we did in the previous show where we were pushing it straight from Visual Studio Code. But very, very cool. That's how we can do it entirely from GitHub Actions. And now every time I was to do an update to this, I could push a new version, this workflow runs, it deploys, and it's all happened straight from Visual Studio Code and our GitHub repo. So if you're new to DevOps and you decide you do want your CICD pipeline slash workflows or whatever you want to take advantage of this, you now have options. You can do it from GitHub. You can do it from Azure DevOps, codes in the same place. You can kind of choose which one you prefer. If you're already doing Azure DevOps, you may decide you like this better, move over, you may decide to run some in one place, some in another, it's an option. Exactly, and that's what it's about. It's about having options, making sure that you've got the right tools to empower you to build what you need to build, not just, this is the only way that I can go down the path. Right, and it's for people that are already in GitHub, it's nice to be able to do it from there, as opposed to saying, okay, now what tool do I use to do my CICD? I can just do it straight from in here. Exactly. Fantastic. Yeah. Awesome. Glad to show you how to set up a GitHub action from scratch. That was the best 20 minute overview of GitHub actions ever. Exactly. Might think about doing more of a deep dive on this, so we'll have to think about that. Yeah, yeah. You guys let us know if that's something you'd want to see. Yeah, like I said, there's a lot more stuff that we can do with it, particularly when we try and integrate with other things that GitHub can do, whether you're working with your issues or projects, pull requests, we can have all of those things trigger off different sets of workflows. Okay. Cool. Thanks so much for doing this. Thanks for having me. Hope you guys enjoyed that and we will see you next time on Visual Studio Toolbox. See ya.