 As a developer, I love automation, especially when it comes to continuous integration and continuous deployment processes. Why? Well, one of the primary reasons is because it automates and orchestrates repeatable processes in a very reliable and predictable way. I also love Azure Function Apps. In this video, I'm going to marry the two topics. I'm going to show you how I implement continuous integration and continuous deployment in my Azure Function Apps to deploy new and updated functions to Azure, provided I have a green bill with passing tests, as well as automate the entire process of creating or updating the necessary Azure resources using infrastructure as code with Bicep and the Azure Resource Manager. Hey, I'm Andrew Collins. This episode is also available as a blog post on voitanus.io and as a podcast on voitanus.show. Check out the description below the video for links to these other resources. If you're new here, subscribe to get notified of my future videos for professional developers on Microsoft 365 and Azure topics. Hi, I'm Andrew, and I love automation and orchestration aspects of CINCD in the development projects. Why? Well, I love it for a bunch of different reasons. First, I love how I can create a gate that only deploys the project when all my tests pass. Second, I don't like writing documentation in the pros style. I think it takes a lot longer to read a pros style documentation than it does to look at really descriptive code. Automated tests explain precisely what is and is not expected from a component that I'm testing. In workflows used for deployment, document the process of how and in what order things should be deployed. The other thing that I like about the CINCD process is that when you leverage infrastructure as code or IAC, the environment that you deploy isn't just spelled out in code that documents precisely how the resources are configured, but it also makes the creation of those resources repeatable and thus reliable because it's predictable. Not only that, but the files involved in infrastructure as code, they can be versioned and kept along with my project. In this video, I'm going to show you how to leverage all of this with an Azure Function app project by utilizing GitHub Actions and a bunch of other stuff. Now, before we get started, let me set the stage for what we're doing so you have a good picture on where we are in this entire process. First, when I push to the master or main branch, I want a workflow to run all of my tests to verify that I've got a green build. That's the continuous integration part of my workflow. The second thing I want is that provided it's a green build, I want to verify, create, or update all the resources in Azure that my project depends on. This is the infrastructure as code part. Let me show you what this looks like in my project. Here I've got a folder called Infra. If I look at that and I click on the main bicep.file or the main.bicep file, what this is is this is an Azure bicep file that is going to be used to provision my resources. Bicep is just a domain-specific language or a DSL that essentially sits on top of the Azure Resource Manager or ARM. When I compile this bicep file, it's going to generate an ARM template for me that I can use for my deployment of my resources inside of Azure. There's a lot of benefits to Azure, and I'm not going to detail everything about why I love bicep. Instead, I actually talk about it in this video up here, where I walk through creating the exact same bicep file that we're going to use in this project. I'll also include a link to that video in the notes below the video. There is one change that I've made to this, and I'm adding in an additional resource that you see right here. What this resource is going to do is it's going to create an Azure resource called the App Configuration Resource, and that's just a place for me to store name value pairs of settings for my project. It also integrates nicely with Azure Key Vault if I want to store any secrets there. But the thing that I like about it is that I can label different values of a setting, so I could have like a connection string and have that be for a production connection string or a staging connection string to give these different labels. What you see here is I'm creating a new Azure configuration resource, sorry, an Azure App Configuration Resource. I've given it the name, whatever the prefix I'm using for all of my resources I provision as dash app config. I'm setting it to the same location as where the resource group is, and then I'm setting my two keys. So the first key is called the app version key, and I'm setting a default value of that equal to just 0.0.0, and then I'm also going to set one for the commit hash, which is just a whole bunch of zeros. When I do my workflow, when my GitHub workflows run and I deploy to staging or production, those values are going to be dynamically set. Another thing that I had to do with this is that if I scroll down to the very bottom, is that I'm leveraging something called managed identities inside of Azure to where I want my Azure Function app. I want that to be treated as an identity and give it access to that app configuration resource. And I'm doing that through another bicep module that I wrote here. So this is my grant app service to app config. And what I'm doing is I'm passing in three parameters. I'm passing in the ID of the app configuration resource that I've defined. I'm passing in the ID of the function app and I'm passing in the principal ID of the identity of the Azure Function. And if we look at that bicep file, what that does is I'm first going and obtaining and a reference to the out of the box role that Microsoft has created for the app configuration resource. It's a role called the app configuration data reader and it's got a very specific idea associated with it. So I'm getting a reference to that resource and I'm doing that using the existing keyword in bicep. And then what I'm gonna do is I'm gonna create a new role assignment to where I can marry up the Azure Function app to the app configuration. And I'm doing that by creating the role assignment. And so here I'm saying that this role assignment is scoped to the resource group that I'm giving it a unique name. I'm giving it a GUID and I'm using how to create the GUID based on a couple of different parameters I'm passing in. And I'm saying I want to do that with, I wanna create this resource using this role definition that we just obtained above. And I wanna set it to a service principal is the principal type and the principal ID is the identity of the function app. What does this do? Well, now I don't have to use credentials. I can just have my, as long as my function app, the code that it's running is gonna have reader access to the app configuration. It just allows me to avoid having to use connection strings and secrets or passwords and stuff to be able to log in. So it just makes it a lot, my application a lot more secure. Essentially, the function app can query the app configuration resource. So that's my main bicep file. And as a reminder, this bicep file also calls another bicep module that's gonna set all of the app settings on the staging and the production deployment slots. Again, if you wanna know more about bicep and how I use it to provision all these Azure Function resources, check this video that I'm gonna link to in the video or I'll also include a link to it in the description for this video as well. Now, the last thing I want to have happen is that once all the Azure resources are created, I then wanna deploy my functions app code base to the Azure Function apps staging slot and I can do that for just testing and such. But why stop right here? Let's keep going and let's automate the rollout to production. So to do that, I've got one or two things I'm gonna do. The way it's gonna work is that when I tag my repository and push that tag to the GitHub repo, I'm gonna have a workflow that's gonna run and create a new release in GitHub, but it's gonna leave that release in draft state. And this is gonna allow me to modify the draft name, the description and explain what's in this release. And then the next thing I'm gonna do is that when I publish the release, another workflow is gonna fire and it's gonna handle the swapping of the production and the staging slots of my Azure Function. So enough talking, architecture explanation, let's get to it. All right, let's first look at my project that I've got on my laptop. And this sample project has two Azure Functions inside of it. It's got one called heartbeat and it's got one called simple math. Both of these guys are very basic. The heartbeat function just writes out the contents of a setting in an Azure app configuration instance. So you can see that here where I'm gonna log in, getting the default Azure credential. I'm then gonna go connect to the, or get a client for the app configuration using the app configuration that I've defined. And then I'm gonna grab the app version and the commit hash, those two settings from the app configuration. And I'm simply gonna write those values out to the response. So it's gonna give me the app version and the commit hash. That way we can see like, are we on a production slot or a staging slot, et cetera. Now the simple math function is interesting as it's got some tests and it leverages Azure app insights to track this entire request. So I'm gonna explain how I do this in another video which I'll link to in the description below and I'll link to it up there as well once it's available. So if you don't see anything up there just yet, make sure you subscribe to the channel to get notified when I publish it on this channel. But the point I wanna make here about it in this video is how the settings are used to configure app insights. So the simple mass index file, it initializes app insights and it does that through a call using something I've written called the app insights utils init default config. And if we take a look at that method real quick, you can see how I'm using the telemetry initializer to include in the deployed project version in every bit of telemetry that's sent to app insights. And I'm doing that by first again, I'm logging into, I'm getting an instance of a client that's connected to the app configuration. I'm gonna fetch the app version for whatever version of the app that we're currently looking at. Are we looking at the production version or the staging version of our app depending on the slot that we're in. And then I'm gonna set a context tag equal to whatever the application version is to the version that's in that setting. So what's cool about that is that every single time that I have a bit of telemetry that's sent to app insights, it's gonna include the version of the app where that telemetry was sent from. So was it from staging or was it an old version? So if there's a bug that I've already squashed, I wanna make sure I can filter that out when I look at app insights. Let's start by making sure that everything works by first running all of the tests for my project. So the first thing I need to do is I'm gonna need to prep my builds or my project. And so what I do is I've got the, I'm using Jest for all my testing. And so I needed to compile or transpile my Jest config.ts file down to JavaScript. And I'm gonna do that using this little prep script that I've written. Now after transpiling my Jest.config.ts file to JavaScript using my prep script, I ran the test and I can see that all of them are passing. The code coverage isn't great because we only have tests in one of the functions. Let's just chalk that up to do as I say, don't do as I do. So our project is good to go. So let's push it to an empty repository. I've set up for my GitHub account. I'm gonna start by adding the GitHub repo as a remote on the local project. And I'm gonna push all my code up to it. Okay, now we got our project inside of our Git repo. So we're ready to go ahead and get started. Now before I create and test a workflow, I need to do a couple of things in Azure first. So first I need to create a resource group where I want my Azure function app to go. And I can do that using the Azure CLI pretty easily. So to do that, I'm gonna run AZ group create and then pass in a name and then I'm gonna set the location equal to East US. And then I'm gonna add a couple other tags to it as well. And here if I jump over to Azure and I refresh the resource groups page for my subscription, I can see my resource group that I created called Sunshine Peacock. Now the other thing I need to do is I need to create an Azure AD app that the workflow is gonna use to create the deployment and interact with the Azure function app that the deployment is gonna create. So I'm gonna head over to Azure AD to my Azure AD tenant on the Azure portal and on the app registrations page, let's create a new app. Now next on the certificates and secrets page, we're gonna configure this app with a federated credential. And this is a really slick capability that exists between Azure AD and GitHub. What this is gonna allow me to do is basically configure this app to automatically trust GitHub credential with specific attributes that are defined when it requests it. So from my workflow, GitHub is gonna use the OpenID Connect protocol to authenticate with Azure. And the request from GitHub is gonna include a bunch of other information on who's requesting this token and where it came from, like my repository and the branch name. So what I'm gonna do is I'm gonna set the federated credential scenario to the GitHub actions and set the organizations to my GitHub organization. I'm gonna set the repository to the name of my GitHub repository and the entity type is gonna be set to branch. Now, based on selection, I'm gonna set that to master. And what all of this is gonna do is effectively gonna say that if GitHub tries to authenticate from the master branch in this repository for this organization, we're gonna allow it and we're gonna let them get the token that they're requesting. So I'm effectively saying this app is tied to the master branch on the repo that we're working with. So what this does is this tells Azure AD that we trust GitHub requests for an access token via an action that was triggered on the master branch in a specific repository. So when it does it, go ahead and trust it. So now when my workflow authenticates, it's gonna authenticate as this app. The best part of this is there's no secret or certificate to keep track of and thus expire. So because all GitHub needs are the IDs of the Azure subscription, the tenant, and the ID of the app to know who to authenticate as. So that's even more secure than keeping track of a secret. It's basically treating my master branch in a very specific repository as a managed identity. That's really cool. So to give the workflow the ability to create these resources using this Azure AD app, I need to go to the resource group that we created and grant this app the owner role. And that's gonna be able to allow it to create deployments. This is leveraging the whole RBAC support that we have inside of Azure. So I'm gonna do this from the resources access control IM screen. I'm then gonna select add a role assignment. I'm gonna select the owner role and then I'm gonna add the Azure AD service principle to it. And now when I look at the role assignments, I can see that my Sunshine Peacock bot has owner role over this resource. Now the last step is to add some secrets to our GitHub repository so that the workflow can authenticate as the Azure AD app and define the resource group where they're gonna be created. Now I can do this in the GitHub UI or I can use the GitHub CLI to do this, which is what I wanna do. So I'm gonna include a link to the GitHub CLI in the description below the video in case you haven't seen that yet. So I've already installed it and I'm already logged in. So I'm gonna plug in the values of the subscription ID, the tenant ID and the app ID for the app we just created. All these values I can get from the homepage of our app itself, the app overview page. So there's the application ID, the directory or the tenant ID, and then I have to go fetch the subscription ID. Next I'm gonna set the secret for the resource group that we created and I'm gonna do that using the same setup. So I'm gonna go fetch the name of that resource group that we created called Sunshine Peacock and just make sure we get the exact name and I'll go ahead and add that as a secret as well. And finally, I wanna set the prefix name that I wanna use for all the Azure resources that are gonna be created in my deployment process. And just to confirm that these are all set, we'll come back over here to GitHub and I'll go to my settings for the repository, I'll go to secrets and go to action secrets and we can see all those secrets that we just created in the last minute. All right, now that everything is set up, so I can create the GitHub workflow. Now GitHub workflows go in a folder called .github slash workflow in my project. So I'm gonna go ahead and create that and then I'm gonna create the workflow file. I'm gonna name it the test deploy to staging .yaml file. And with the file created, I'm gonna give the workflow a name and then I'm gonna configure it when it's gonna run. So I'm gonna set this to only run on when there's a push to the master or the development branch. Next, set the environment variables for the workflow. And I like to include the secrets that I'm depending on existing in the GitHub repo as well just for reference, I just leave them commented out. Now one variable I like to create is one here called the deployment name. And that's just a string that contains the ID of the run in GitHub. Later I can use this to see which workflow run triggered which deployment in Azure. I'll show you that later when we get to the part of testing everything. The last block of the variables that you see down here, those are the ones that'll be dynamically created and set from within the workflow. And that's gonna be from the result of running the deployment job. It's gonna have a bunch of outputs from our bicep file. And I wanna be able to grab those things. Now finally, the last thing that I need to do before I create the jobs is to tell GitHub what permissions the workflow is gonna need. And this is what's triggering GitHub to issue a request using their open ID connect support to Azure AD using our Azure AD app that we created previously and gave it permissions to our resource group. Now the first job to create is the test job. So let me copy and paste this in and explain what it does. What this does is it's gonna get the name of run all tests and you can see its ID is named test here. I like to use this little condition so that I can check to see in the commit that's triggering the workflow to run to see if there's a specific string there. And if there is, then that allows me to bypass this job. So if it's just a simple commit and I don't need a whole CI and CD process, I can say don't do it. And in my case here, I just have with square brackets surrounding the string skip-ci. So if that's in a commit message that's triggering the workflow, it'll stop running the test job. And you'll see that all the other jobs in this workflow are dependent upon tests succeeding. So if it doesn't run, nothing else is gonna run. I'm first gonna go check out the full code base. And I'm making sure to do it nice and quickly. So I do it just using, saying I only want to do the fetch depth of one. So don't get all the commits, just get the most recent one. And then I'm gonna set up my node environment. I had an environment variable that I set for which version of node that I wanna use. In this case, I'm using node 14. So I'm just saying go ahead and go grab that. I'm then gonna go use the caching support that we have with GitHub to either restore all the dependencies from my node modules folder or I'm gonna go install all the dependencies. And what this does is this is just simplifying and speeding up the process of refreshing the npm install command. So in this case here, what I'm doing is I'm creating a key that I can use to see has anything changed. And the way I do that is by making a combination, concatenating a bunch of strings together. So I'm using the things like the operating system that I'm running on. In my case, I'm using Linux dash then version of node and then the node modules folder name. And then I add in a hash of the file package dash lock.json. So the next time I install something an npm package into my project, it's gonna change the package.lock file which will change that hash which will invalidate the cache and it'll go do a new download, a new install. This guy had this actions cache GitHub action has an output variable that will say if it hit the cache or not. So if it hits the cache, then we don't wanna do an npm install. So what I can do here on the next step when I'm installing the dependencies, I can say go look at that step. So the idea of that step was node module cache. So I'm saying look at the steps, look at the node module cache, his outputs and see if the output property named cache hit. If it does not equal true, then we had a cache miss. So we didn't find what we were looking for either it's the first time it's being run or my key for the cache change like I installed an npm package from the last time I ran it and that's gonna go ahead evaluate to false and so it'll run my npm install command. I then build the project, I'm pretty straightforward just doing a build task and then I'm gonna go run all of my tests. So here I'm just running my test using an npm script and then at the very end I'm going to save all of the code coverage results as just an artifact with this job. So I can go back and download those if I wanna look at that. One of the things too that you'll notice here is that I heavily use emojis in my descriptions for my different tasks. So for example, when I'm setting up node, I use a wrench, when I'm restoring everything I use like the recycle icon when I'm downloading stuff, use the down arrow when I'm building it, well obviously we're developers we pray to hopefully everything works. Testing it uses a test tube and then saving is just using a document. I like doing this because you'll see when we look at in GitHub it's really easy to see what's going on and what stage we're in. Now the next job is to deploy all of my infrastructure. So I'm gonna set the dependency of this job to on the test job so that it only runs when the test job is going to succeed. What this does first is it's going to check out the code base and the logs into Azure using the Azure login GitHub action. And this action is using the OpenID Connect support that GitHub includes and the credentials that we pass in from our secrets that we saved to obtain the access token. We save those secrets in our GitHub repository if you remember from our previous step. Now the last step is where we're gonna create the Azure resources using our bicep file that I showed you how to create in that other video. Notice that the two deployment name environment variables I'm passing in one of them is the name of the deployment that we set in our environment variables at the top of the file. And this is gonna have the name that includes the workflow run ID but it also includes a prefix to indicate that a GitHub workflow is what's triggered it. The other one that we have, the deployment name ID, that's the run ID. And that's included in my bicep file as a parameter because any bicep modules that my main bicep file is gonna call is gonna get this in their name. And this is gonna make it so I can easily look at all the deployments when we go over to Azure and I can see that all of them that were associated with a very specific run that we had from our workflow. And the last job, that's to deploy the app. Now this job has a dependency on both the test and the deploy infra job. So both of those must succeed before this one runs. And the bulk of this one is pretty straightforward, checking out the code base, setting up node, restoring the node modules cache or running npm install if the cache wasn't found and then building the project. Now let's get to the fun stuff. It's then gonna sign into Azure with the CLI using the same Azure login action using the same federated credential that we used earlier. And the next step, now the next step gets the outputs from the deployment job and it saves the values as variables within my workflow. Now it does this by storing the output of a query using the az deployment group show command. And I know what the deployment name is because we ran it in the previous job. So I can query for a specific value in from the deployment section of Azure that I executed previously using that bicep file. I'm looking for a function app name property, the name of the staging slot of the function app that I created in the bicep file and the name of the Azure app configuration resource that I created. So I'm grabbing all three of those values and I'm stuffing them into three different variables. Those are variables that I defined above as well if you recall in my environment section that I just said we're gonna set these dynamically. So I'm fetching those from the results of running the deployment job. And then to deploy my function, I also need to get the publishing profile for the function apps staging slot. So again, I'm gonna use the Azure CLI to retrieve this XML from the function app and I'm gonna store it as an environment variable in our function. So I'm kind of doing the same thing I just did a second ago. I'm running a script using the AZ CLI and I'm taking the results of that and stuffing it into a environment variable for this workflow that I can use. And this isn't terribly ideal because the publishing profile can aid some credentials and because I'm storing it in an environment variable and it's no longer, it's not a secret then it's being stored in the log that's clear text. So I just wanna mention that that is a potential vulnerability but it's one that I'm not too concerned about because the only people who could see it are those who have access to the logs for this workflow. And I also have a practice where I clean up the artifacts from a job so I can't see the logs after like a week or two. So they're only around just to check if there's an issue. Now to do this, I'm using the same output values that we just retrieved in the previous step from the deployment process. So I've got things like the slot name and the function name. And once I have the publishing profile I can use the Azure-functions action GitHub action to deploy my app. Now these last two steps this is like some special sauce that I like to add. This is my Azure app configuration resource contains two values or two settings for the version of the app and the commit hash from the repository that's currently deployed. And I'm using the Azure CLI to set the value of the staging label for these two different settings. All right, so let's see it work. I'm gonna save my workflow. I'm gonna push it to the repository up in GitHub. And actually I noticed that we had a little bug here and I forgot to actually set the branches on here. So while I have on the start part of my workflow I said on push I needed to have one more thing here for branches. And so what branches do I wanna support running to? Just forgot that one keyword. So I go ahead and save that and push those changes up. And here we can see that now our workflow has started. So we can see our three jobs. We have our running all tests, deploying infrastructure and deploy to Azure Functions app. So we'll go ahead and take a look at this first one and we'll watch this guy run. So we can see here that all of our tests pass and the build work, the NPM install work and all of our tests pass as well. So now we're onto the stage of deploying our infrastructure. So let's go over and take a look at that step because that's gonna start running now. Here we can see that our infrastructure job has also completed. So we logged into Azure successfully. We ran our deploy infrastructure job and we completed the job as well. And we can see that our Azure Function app is now starting to be deployed. But while that's going on, let's go jump over to our deployment and let's check it out real quick. So I'm gonna come over here to our resource group. And if I look at our list of deployments, we can see that we had three deployments. Now, if you recall, my bicep file, the main bicep file that we called from our GitHub action, it was, that main one was actually calling two other bicep modules. And every time it calls a separate one, those are independent deployments. So you can see we gave our workflow or our deployment job, we gave it a name. I called it my gh underscore CICV underscore and then the ID of the workflow run. And we can get that ID from the URL of the run. So over here, if I go to our summary of this, we can see that the run up here ends in 224. And if I jump over here to back to my resource group, we can see that it ends in 224. So not only that, I also passed in that ID as a parameter to this deployment. So I then included it as part of the name for the two other modules that my bicep file was calling so that I can tell that all three of these went together. So if I look at this first one, we can see that our inputs that we passed in, the prefix was Zara, the deployment name ID was that same GitHub workflow run ID. Everything's deployed to East US. We have a bunch of outputs like the app insights instrumentation key. There's the name of our Azure application configuration resource, there's the name of our Azure function app and then there's the name of the staging slot. And if I come back over here to the resource group and I look at all the different items that we have, here we are, we've got all of our different resources that have all been set up. I can go look at the Azure function. I can see that we've got a pair of deployment slots right here. We have our primary one and our secondary one for staging. I go look at staging. I can look at the configuration for the configuration. We can see that I have all my app settings that are listed here as well as like unique value for one that's set up with a staging slot. So that's gonna be different from our production slot. We can also go over here to our resource group. And if I go look at the app config resource that we created and if I look at his configuration explorer, what we'll see here is we also have our two default keys that have been set up. So we have our app version and our commit hash with the default values of just zeros and all zeros for the commit hash. And notice there's no label set here. So once our staging deployment runs, it should update these two values or set new values using the label staging so that we have a separate value that we can look for with this. Let's go back over to our GitHub workflow. Let's see where we are on the Azure Function deployment. And we can see here that our deployment is still in process. This is also a good way to see how all of these different emojis that we're using here, it makes life a little bit easier to be able to quickly see what's going on. So I can easily see where the login is happening with Azure using that key that when I'm pulling out the output variables from the deployment job, I'm using a magnet here to kind of pull those things out. We can see where we did the build, right, everything works, et cetera. So we're still going through and we're still in the middle of the deployment. This can take a little bit of time when we do a deployment. This is probably the longest process, which is interesting that it is the longest process considering the creation of all those resources only took about, I think it was only about two minutes. Let's take a look here. Yeah, it only took two minutes to do the entire infrastructure deployment to log in and then create all those different resources here. So it looks like our function got deployed, but we ran into an error when we were setting our application configuration settings. So let's go take a look at that. Let's open up and see what it says. And it says that our argument, the name expected one argument, we can see we're passing in the name here. Now, oh, but look at that, but it's blank. That's interesting. So let's go take a look at our function, our GitHub workflow and let's see what happened. So if I scroll down to the part where that is, we're gonna do about a live debugging here. And here's our configuration value and it's a secret. We haven't set this secret, but we shouldn't need this secret because I'm pretty sure that we, yep, we were pulling it out as an environment variable. So we don't need this as a secret here. Instead, what we needed is this really should be an environment variable on these two values. Because remember, we're pulling this out on the fly when we do the extraction from the results of our job where we were also getting our function name and you see we were using those as for our settings there. So this really should have been an environment setting. So let's save that change. I'll come over here and say, we'll update the name for AZ app config and the workflow and I'll go ahead and push those changes. Now that our deployment has been fixed, we're gonna come over here and look at our Azure Function app that was created. And I'm gonna come over to the staging slot and we'll look at the configuration of our staging slot. And what you'll see when I show the values here, what you'll see is that the configuration label has been set to the staging label. Now I can also go over here and look at my functions and I can see my two Azure functions that have been deployed. All right, so those are all up and running. We're in good shape there. If I now come back over here to our resource group and I look at the app configuration that we created and I look at his configuration explorer, we can see that we've got a couple of different values here. We see we have a staging label set up. And so if I show all the views for it, we can see that when we query for the staging label for the key app version and same thing with the commit hash, the staging label, we're gonna get values that we want to see just in staging. Now after this initial deployment, we need to add one more secret to the GitHub repo, the name of the Azure app configuration resource. And the reason we have to do this is because that we're gonna be updating the values of the production settings when we do a deployment. And right now these workflows run separately than the one that we just created. So we don't have the context of the name of the deployment to query the different outputs that came from our deployment. So the way I'm gonna do this is I could use the GitHub browser interface or the CLI to create the secret. So I'm gonna use the CLI to do this and this is the name of our configuration. So I'm gonna go ahead and grab this and I'm just gonna run this in my, run this in the command prompt and I can look at the secrets that we've defined for our project and we can see that we have the app config name has now just been set. Now, well, this is all cool. Let's go further and let's see how to automate the swapping of the staging and the production slots. Let's drop two new workflows in the repository and I'm gonna push them up to GitHub. Now the first one, draft release YAML workflow is gonna fire when a new tag is pushed the repository and it creates a new release in draft mode on the repository. And what this does is it's gonna give me a chance to set the release name and the description of what's included in the release. So now that I've pushed a tag, let's go take a look and see that in our project. So I come over here to the code view and if I look at the releases, I can see that we have one release here of the 1.0.1 release that's in draft mode and that was kicked off here by our release workflow. So we can see here that we drafted a new release and creating a new draft release just simply got the tag from the push and then it went through and it created the new draft release. So again, I'm over here and I can see the releases here. Now let's look at the deploy release workflow. Now unfortunately I've got one secret that I need to create and that's the trusted credential support that Azure AD has with GitHub. It doesn't support the trigger that's gonna cause this workflow to run because what this workflow is going to do is that when I look at the deploy release, this is going to run whenever I publish a release. Well, because we just did that with a tag, when I publish this release, it's gonna run for a specific tag, that's its context. And I can't use a specific tag because that would be like I have to go back to the Azure Active Directory trusted credential for this Azure AD app and I'd have to add in the tag name every single time. That's not very doable. So unfortunately I can't use that style of authentication in this case. So instead I'm gonna need to go create a client secret for the Azure AD app and I'm gonna store it as a secret in the GitHub repository. So I'll come over here to my Azure AD app that we had created for all of our uses here. I'm gonna go over to the certificates and secrets and I'm gonna create a brand new secret. I don't care about the description right now and this is our value. So I'm gonna go ahead and copy this value. I'm gonna come back over and add this as a secret. So it's gonna be called my Azure client secret. So go ahead and paste this value in, copy that and drop it in. All right, that value's now been set. If I now come back over to my repository and just verify that the secret was actually set and sure enough there it is. It was updated just now, so we're in good shape. So now with the secret set, let's take a look at this workflow. The first job is gonna first log in to Azure using the client ID and secret as a service principle. It's not like the standard login we were using in the previous workflow. It's then gonna use the Azure CLI to swap the production and the staging slots by calling the AZ function app deployment slot swap command. Now once the slots have been swapped, the next job is then gonna update the production labels of the settings in the Azure app configuration resource to reflect the production version and commit of the app that's running in the production slot. So let's see this work. I'm gonna go to the releases in the repository and edit the draft and then I'm gonna hit publish. And this is gonna kick off our workflow. Here we can see that we are logged into Microsoft Azure and then we are running the swap command using the Azure CLI. And this just takes a minute to finish. Now that the workflow is finished let's check out our deployment. So I can do that by running over to our resource group again. I'm gonna go to the app configuration resource. I'm gonna look at the configuration explorer. And this time we're gonna go ahead and expand everything and show all the values. And here we can see we've got our default value of all zeros for that version. If we're in staging we get the staging label or the staging value. And if it's a production environment or production label we're looking for then we're gonna get the 1.0.1 label. And we can see we've got a couple of different commits that are actually being used here. And it's because of when we swapped slots of which ones were being used at that time. It's pretty cool, isn't it? So you've now seen a structured deployment of an Azure Functions app complete with continuous integration, continuous deployment processes that also leverages infrastructure's code to provision the Azure resources. And going forward our entire deployment process either to staging or production is entirely handled by pushing commits to the GitHub repos master branch and controlling the rollout to production using GitHub releases. So I don't have to go set any more secrets or anything like that. Everything has all been defined, we're all good to go and it'll all be automated. So what do you think? Let me know by dropping a comment below and let me know if you wanna see more videos about Azure Functions or Bicep or automating CINCD processes with GitHub Actions. If you like this video, please give me a thumbs up and subscribe by smashing that big red subscribe button below the video. That way you'll be able to see when I publish more videos for professional developers related to Microsoft 365 and Microsoft Azure, including topics on Bicep, Azure CD, CI and GitHub Actions. And don't forget to check out my other videos where I show you how to create a Bicep file that I used in the CINCD process as well as my other videos in my channel about Azure Functions and GitHub Actions.