/ Insights / View Recording: Modernizing Legacy Systems with Github Actions Insights View Recording: Modernizing Legacy Systems with Github Actions May 16, 2024Watch our webinar, aimed at developers, IT professionals, and organizations interested in updating their systems with modern practices. We’ll cover how to use GitHub Actions to transform legacy applications into scalable, efficient modern systems, focusing on automation and CI/CD processes. Key Learning Objectives: Modern Web Application Development: Gain insights into the characteristics of modern applications and common architectures. Understand the critical role of Continuous Integration and Continuous Deployment (CI/CD) in modern development cycles. Deep Dive into GitHub Actions: Explore the fundamentals of GitHub Actions and how it stands as a pivotal tool for modernizing applications. We’ll walk you through setting up GitHub Actions for a demonstration application, highlighting how to craft advanced workflows that streamline development and deployment processes. Application Containerization: Discover the basics of Docker and containerization, a cornerstone technology for modernizing legacy systems. Learn how to containerize a demo application, making it more portable, scalable, and easier to deploy across various environments. Automated Deployment to Azure: Delve into the world of Infrastructure as Code (IaC) with a focus on Bicep, and explore Azure’s hosting options for .NET applications. Witness first-hand how containers can be deployed to Azure, showcasing an end-to-end automated pipeline from code changes to production deployment. Why Watch? This webinar is more than just a theoretical exploration; it’s a practical guide designed to empower you with the knowledge and skills needed to modernize your legacy systems effectively. By integrating GitHub Actions into your development workflow, you can automate mundane tasks, improve efficiency, and significantly reduce the potential for human error. Whether you’re a developer seeking to upgrade your skills, an IT professional tasked with system updates, or an organization aiming to modernize its IT infrastructure, this webinar is tailored to meet your needs. Transcription Collapsed Transcription Expanded Welcome everyone. Today we’re gonna be talking about a modernizing legacy systems with GitHub actions. So kind of the goal of this presentation is to be. Kind of an overview of some modern application principles, and then we’re gonna dive into more of the actual GitHub actions. What you can do with them, how the platform can be used to benefit your cicd process and some cool things that you can do kind of. The goal is to really, you know, give an introduction for those that maybe new and then also provide some maybe some tidbits for some of those people who may be more advanced in the in the subject. So we’ll go ahead and get started with some introductions here. So my name is Sean Lawton. I am a software engineer here at concurrency. I’ve been here for about 2 years now. I’ve been in software development for about 5 1/2 years. I work on the modern applications team where we deal with a pretty wide array of. Clients and projects from smaller business applications to custom SAS solutions and other enterprise applications. And then if you see on the slide there, I do have my LinkedIn URL there, so feel free to connect with me. Shoot me a message if you have any questions, I’m happy to answer them. And then also you can just post any questions you have in, in the chat and we’ll go ahead and answer those towards the end or during during the webinar. So, Nick, I’ll let you introduce yourself. Nick Woods 2:03 Right. Yep. How’s it going, everyone? My name is Nick Woods. I’m a senior software engineer here and I’ve been in the software industry for six years, so I’ll be mostly handling the tech side. So. So mostly Shawn show. But again, we’re here to ask and answer any questions you can connect with me on LinkedIn and I’ll hand it back over to Sean. Sean Lawton 2:24 Alright, great. Thank you, nick. So yeah. So for today’s agenda, we’re gonna be covering a few topics. Uh, the first topic we’re going to be discussing is more of just some of the common architectures that we see in the applications that we we build custom and then some of the ones that we kind of maintain. And then the next item we’re gonna cover is containerization with Docker and other tools. We’re going to cover infrastructure with Azure bicep, which is a cool. Kind of language that you can use to provision resources. That is kind of an abstraction on top of. Azure Jason Arm templates makes it a lot easier, so it’s pretty cool. And then finally, we’re gonna discuss DevOps and the continuous integration continuous deployment process that can be enhanced with UM, GitHub actions platform. We’re gonna do kind of a a a deep dive into GitHub actions. We’re going to discuss the basics and then towards the end, we’re gonna go over a more advanced example that kind of wraps everything together on one. Alright, so some of the comment architectures, UM that we see, umm, you can see on the on the right side there, we’ve got there’s about six of them listed in the diagram. Most of the ones that we we work with on a day to day basis basis are monolithic architectures and then also microservices and clean architecture. So monolithic architecture is more of a single tiered software architecture where all the components are kind of unified. So like in your interfaces, your business logic, your data layers, your infrastructure layers are all united and one generally your services are all gonna be calling the same database you’re gonna be deploying that entire project as one unit. And you know, some of the advantages of a monolith architecture is it’s it’s easier to to maintain and you know some of the some of the architects that we work with, we’ll agree with me there. But also it can be a little bit more difficult as your project gets larger and larger. It can be more difficult to maintain and to scale, and that’s kind of where the microservices come in and they shine, right. So I think within the last like maybe 10 or 15 years, microservices have become like a bigger thing as the cloud adoption has came through and you can kind of think of microservices as individual units that are kind of self contained, right? So if you look at the diagram on the right, the 2nd on the right side, you can see that there are four services inside of UM that architecture and each one have their own database and their it’s you can kind of think of them as like their own contained unit. Each of them can be deployed independently, so you don’t have to. If you make a change to 1 service, you don’t have to worry about, you know, redeploying the entire project. You can just deploy that specific service and like I said earlier, the kind of main benefit to microservices, it provides a lot better scalability as your project grows larger and larger. And if you have like distributed teams working on specific tasks or specific services, it makes it easier in that regard. But it’s also does not come with without its faults, right? So it’s it’s more difficult to maintain. You know, if you have a smaller, smaller team and honestly, it really just depends on your use case. You know, for the most part, you’re probably not going to need to use microservices, but you know if if your use case requires like high throughput or you know a large services that need constant update and you know that then the microservices architecture can really, really give you some some benefits there. And the last one that we’re gonna talk about is clean architecture or layered and some people call it the onion architecture. We’ve been working with this. I have been for the past two years on a couple of projects. I find it really interesting. It’s it’s not so much an architecture as it is kind of a software development pattern that you can use inside microservices and also monolith. So if you wanna go to the next slide can. Kind of visualize it here. So this is kind of the visual diagram of what clean architect clean architecture intends to. Capture here. So if you look at the red circles, we’ve got the domain layer and the application or the business use case layer. So that’s called the core of of clean architecture, right? So kind of the goal of this whole pattern is that the core can remain the same and the outer layers can be interchanged with different. You know, if you have different databases or web interfaces, things like that or presentation layers, you can change those without affecting the inner core of of the architecture. So the domain layer is mainly made up of, you know, your domain models, your enumerations, your events, your exceptions, things like that that aren’t really gonna change, you know. And if they do, it’s not gonna affect the OR it’s it’s gonna be contained inside that core layer, right? So the application layer, the one right around the domain layer, is going to have a project reference, at least in net it’s gonna have a project reference on the domain where and it’s able to, you know, use those domain models or those enumerations, etcetera. Inside of that application layer, and that’s where your business logic is gonna lie. And you know, and that’s where the outer layers can call in. So for example, if you have think of like a Web API, right? If you have. Controllers in that API. Those controllers can call the business logic inside of the core and you can kind of interchange it. You don’t have to worry about, you know, changing the the outer layers and then that having effect on the core of the application is that’s all kind of self contained. Umm. Now clean architecture is language agnostic. I think it’s it’s definitely more popular in the net space. And it’s also very highly testable, and you know it’s it’s, it’s where it really shines is when you have larger projects where you know as the project grows, you know exactly where things are going to be. You know exactly how things should be laid out. Obviously that kind of comes with the added. Complexity on top, so it may be more difficult to pick up, but it’s definitely something great to know and it’s it’s helped out in a lot of use cases that we’ve had, especially on our modern apps team. So the next thing that we’re going to discuss here is Application Containerization:. Now containerization, is another really cool kind of paradigm in software development, where you can think of it like shipping containers on like a a docker Harper, where you have these containers that can go on container ships and can be shipped off anywhere. You don’t have to worry about what’s inside the container. You know that the container can just go on any platform and and go out to where it needs to go. So if you think about that in software terms, container is basically umm and encapsulated. Kind of mini computer that only has the necessary things that it needs to build itself. You know, it runs. It can run on any OS. It can run on any type of platform, whether that be physical, virtual or cloud, and it really just helps to enhance the development pipeline from you know, the developer to the actual deployment. It’s super easy to use and Docker makes it really great. Nick Woods 11:56 It’s interjecting real quick. Yeah. So it’s kind of coming back to the like the legacy, you know, application, monitorization. Sean Lawton 11:58 Yeah. Nick Woods 12:01 This is like a really good strategy for say you have like an old model within applications running on a on premises server wouldn’t move that to the cloud. Sean Lawton 12:02 Umm. Nick Woods 12:10 This kind of helps you put it inside of a container. That kind of kind of kind of kind of pretends that, you know, kind of sets up the same environment of where it was running previously and then you can just lift and shift that strikes the cloud and it kind of work and then you can kind of modernize it incrementally later and that kind of gives you off the ground. Sean Lawton 12:29 Exactly. Yep, that’s a great point. And there are some also also some services out there that provide you know scalability with orchestration like urinates that everyone knows and loves. So yeah, so the next thing we’re gonna talk about here is infrastructure, specifically with Azure bicep. So some of you may be familiar with Terraform, which is more platform agnostic, but we’re going to be talking specifically about Azure bicep here, which is kind of an abstraction layer on top of JSON ARM templates. It makes it makes defining and deploying resources to Azure much more modular and much easier to manage, and it doesn’t require the same verbosity that. Jason Arm templates require. So basically what happens is you define your resources and you can also parameterize it inside of the Azure bicep modules or the Bicep, files and that gets transpiled into JSON arm templates which goes to the resource manager, Azure resource manager and ultimately gets deployed to Azure and later in this webinar we’re gonna kind of see how we can do that with umm, how we can deploy our Azure bicep infrastructure with GitHub Actions all inside of the cicd process. In you know it makes it really easy, so if you if you have changes that you need to make to your Bicep, files, you don’t have to worry about, you know going out and manually redeploying infrastructure for all of your different environments that you have. You can define environments. Inside of the Bicep, modules and it just makes it much easier to manage and much easier to maintain when you’re when you’re maybe passing your project on to other folks you know, it makes it a lot easier in that regard. Nick Woods 14:39 You know to for you massively increases the practical replicate that they’ll be able to replicate what you did. Sean Lawton 14:45 Yep. Nick Woods 14:45 So in terms of setting up the environment. Sean Lawton 14:49 And that kind of leads us into the whole CI/CD process or continuous integration and continuous deployment. So kind of the goal of CI/CD is to reduce manual intervention right? So the idea is to automate steps from building, testing all the way to deployment, and one of the best tools to do that is to use the GitHub actions platform, right? So if you look at the diagram below, we’ve got every step from developer to, you know, committing via Visual Studio code to your app repository. That may lie inside of GitHub and GitHub Actions kind of provides that bridge or that gap reduction to deploying your code to wherever it may be. And in our case, we’re gonna kind of take a look at mostly Azure, but you know this works for any type of platform, physical or or cloud based. Umm. And kind of kind of the whole goal of. CI/CD is like I said to to reduce manual intervention to reduce human error and also it makes it a lot easier for teams who may be working on the same project asynchronously to be able to commit to the repository and not have to worry about, you know, messing up any kind of branch. You know, you definitely would. Would have like some guardrails and some branch protections inside of your your repository and in the CI/CD process itself and this kind of goes along with the entire theme here of modernization and GitHub Actions platform provides that that modernization for us. Nick Woods 16:45 Yeah, you have to reach out to a obscene every time you want to deploy something. It’s yeah. Sean Lawton 16:50 Yes, exactly. So CI/CD with GitHub Actions, why spend 5 minutes doing something manually when you can spend 5 days automating it now? But honestly, GitHub Actions is awesome. It’s a great platform. It really helps increase your productivity. And so we’re gonna do a pretty deep dive here into it. We’re gonna go over the basic steps, the basic primitives, and then we’re gonna get into a more advanced example. That kind of wraps everything that we’ve discussed together at the end. So the basics of GitHub Actions we’ve got it’s I think before we get into the basics, it’s important to understand that that GitHub Actions is a platform and there are Actions inside of that platform that help us do things in our CI/CD process. So we’ve got five different. Primitives, we’ve got events, runners, jobs, Actions and workflows, and if you look at the right diagram, it kind of gives you almost like a waterfall view of the process of that you have Actions uses to benefit our entire (CI/CD) pipeline. So the 1st. The first primitive that we’re gonna look at is going to be workflows. If you wanna go to the next slide here. Thank you. I workflows so you can think of workflows almost as their own programs. Umm, it’s basically it’s just a YAML file, right? So it’s it’s YAML syntax now. This YAML file is going to be placed directly inside of the GitHub workflows directory, and that directory is going to be committed to your repo. It’s also going to be automatically read by GitHub, and it’s going to be checked. You know, based on certain triggers or certain events, whether though those workflows should run in any given scenario. You can also define workflows within your workflows so we have kind of a cool example on the right side here where we have a reusable workflow example. Now this workflow, will only run when it is called upon and you can see below where it says on workflow, call there’s two different tags below that with inputs and secrets and those are kind of templated for when you actually do call call those workflows. You can pass it things, so that’s kind of something that you can do almost similar to, you know, developing. You wouldn’t need to redefine that entire workflow inside of a different workflow. You can just use it and you don’t have to to worry about, you know, duplicating right? Don’t repeat yourself. Dry. That’s one of the the main principles of development and that that’s kind of the entire idea behind reusable workflows here. So the next primitive that we’re going to talk about is events, and on the previous slide, the event that that workflow, ran on was the workflow call, right? So right under that on PEG, now an event is just a trigger, right? It’s a trigger that runs as a workflow and it’s specific. Umm. In a specific specific scenario. So there’s a bunch of different triggers that can run a workflow, so the common ones are like pushing to the repo, pulling from the repo, or requests timers and then. I did put a link out there if you wanna click into that, there’s a bunch of other uh. There’s a bunch of other different triggers that we can use to. To trigger our our events that we can use to trigger our workflow, you know in any given scenario we may need. So it’s a really helpful tool. Here gonna have conditionals. You can have dependencies. And there’s there’s tons of documentation that you you can look at that gives you a better idea of what you can do with umm, with the events. Right. And then the next. Primitive that we’re going to look at are runners. So runners are basically just machines that execute jobs, right? So there’s two types of runners. There’s GitHub hosted runners and then there’s self hosted runners. So GitHub hosted runners. What it’s doing under the hood is it’s literally provisioning a virtual machine. And it’s running that specific job and then that virtual machine is being decommissioned all inside of the GitHub host. So if you look to the right, we’ve got two GitHub hosted runners. One of them runs on Ubuntu latest and the other one is just runs on Windows latest and it makes it super easy. You don’t have to go through all this manual work of defining. You know what type of virtual machine you need and all that crap. You can just define it all in the job and the job will will run and then you don’t have to worry about any of that. There is another option that you can use to self host umm the. A runner, but and this may ultimately save you cost if you are using a lot of compute, but you do have to maintain your own hardware software. You may you can use Docker containers and that’s just kind of another option that get GitHub lets you use just a custom self hosted runner, so the next primitive that we’re going to look at our jobs, right? So in our workflows we have specific jobs that are run by default. All the jobs are run in parallel, but you can define specific jobs to run based on specific dependencies or conditionals, right? So each job generally requires a runner, and each job may have multiple steps. So you may have a build job or a deploy job, and that build job may follow. You know a bunch of different steps and the deploy job might not you. Know obviously you’re not gonna wanna run that deploy job right away. You’re gonna wanna wait for the build job to finish, and you’re gonna want it to succeed before you would run that Deployment job. So if we look at the example on the right, we’ve got three jobs here. Job one, job two and job three. Job one does nothing. Job 2 needs. Job one to complete or it runs and then job 3 needs. Job one and two to complete before it runs, and then it’s got kind of an example of just a conditional where you can do tons of different things. You know, based on outputs from the previous jobs or other things that you may wanna use inside of your workflow. And then finally, we’re going to look at actual actions and I know it. It may be a little bit confusing with the GitHub actions platform and then Actions inside of the GitHub actions platform, so Actions are. You can think about our like custom almost applications that run inside of your workflow. Umm, within the the actions platform that you can go to the GitHub marketplace to find any kind of action that may suit your need. So for example, if you want to build a node JS project or a net project, you’re gonna wanna use the setup node action or the setup .net action and you can find all these in the GitHub marketplace or you can write your own custom actions for certain things and that’s also kind of a really cool feature that you can leverage if if you need to. So that kind of covers the five basic. Components that make up the GitHub actions platform. So now we’re gonna kind of look at a simple workflow that we have here. Now this this is a very simple workflow, all it’s doing is it’s running, it’s triggered on a push to the main branch. You can see at the top right under the name that is the event that triggers the GitHub action to run, or the GitHub workflow to run. And then there are two jobs, the build job and the deploy job. Each job is going to be running on the GitHub hosted Ubuntu latest. Runner. And there are some steps that are taken inside of the jobs, right? So the first job it’s using the checkout action. Check out the repository code. It’s using the setup node action like I mentioned earlier to set up node with a specific version of you know node 14, it’s installing dependencies with NPM installed and then it’s running the tests with NPM test. So you can kind of see how the Actions inside of this job work. Instead of having to define all the steps needed to you know, go out and get the node executable and install it, you can just use the umm, the actions you know set up node. It’s super easy and just makes it much easier to read and you know it really helps speed things up. Now if we look at the deploy job, you can see that it’s got this needs. Build dependency so this is gonna wait for the build job to complete. It’s going to run whether it completes successfully or if it complete. If it fails and then there is some additional conditional logic at the bottom. So if you can see there is a run with a pipe and then it says if. Needs. Dot build dot result equals success. Then you’re gonna probably wanna deploy that. If it doesn’t succeed, you may want to do a whole host of other things like. You may wanna send out a notification to someone. You may want to. Generate a report or something of that matter, so it’s kind of just a cool thing that you can do. You can define your your conditionals inside of there and then also define when specific jobs are run. So that’s a pretty simple example here. Now we’re gonna kind of get into some more advanced things. Uh. Umm, so the next time we’re going to talk about our secrets and environment variables inside of GitHub actions. So in GitHub actions you can define your repository secrets and then you can also define environment variables and organizational secrets. So your environment variables obviously are gonna be different between your development, you’re staging your production, your UAT environments, and you can maintain these easily through the GitHub web application. Or you can use the GitHub command line interface and you can also use repository secrets that may be common between all three environments. So if we look on the right, we’ve got a pretty simple workflow here. It’s just called testing secrets, and it runs on a pull request and then it’s got one job. It’s got the Bill of Job that runs on the Ubuntu latest GitHub hosted runner. It’s dumping the GitHub context and then if you look towards the bottom, we’ve got the GitHub token that is grabbed from the secrets that are stored inside of our repository secrets section of our GitHub repository. So just makes it super easy to umm to grab those secrets and you don’t have to worry about exposing and kind of sensitive information. Alright, so the next thing we’re going to talk about here are some really cool use cases that you can use GitHub actions for. Umm, the first one is semantic releases. Yeah, cache management for builds. We’ve got Cron jobs or scheduled tasks, static code analysis, pull requests, notifications, and then there’s a whole host of other things that we can do inside of GitHub actions or that we can use, and this is this a really cool repository called awesome actions that you can go out and take a look. There’s tons of information on here of all these cool things that you can do. You know specifically related to maybe your programming language that you’re using or your text stack. Your test suites things like that. This is a really cool repo that you guys can go out and check out. There’s tons of stuff that you can do here and tons of information. So the first example here that we’re going to look at is just a scheduled job or Cron job or scheduled task and then you can see that all this is doing is literally executing a bash script on or a shell script in side of our workflow. And this is running on a timer trigger and these timer triggers use the Cron syntax that we all know and love. And this is going to run at midnight UTC every single day, and then if you see below that we’ve got the workflow, dispatch tag. Now this this tag allows you to manually trigger the action inside of the GitHub web app, and we’ll kind of take a look at that later, but this can be super useful for things like database backups, automation testing, generating reports, notifications. You know tons of other things, cleaning data, things like that. If we wanna just quickly check out the repository here. Very small repository. All we’ve got here is 1 workflow. That workflow that we saw and it just runs that specific shell script, all it’s doing is echoing Hello World, but you can define obviously whatever you want inside of that script and it will run that on a on a timer trigger. So that’s something that maybe not many people know about. Umm. And it can be super helpful for some of the processes that you may you may have in your workflows. So the next cool thing that we can do with GitHub Actions is semantic release example or the semantic release example, right? So this is going to use the semantic release NPM package to manage releases via commit messages. So there are in semantic release. There are three types of releases. We’ve got major, minor and patch and we can create releases based on a bunch of different conditionals. You know, maybe if you push it to your main branch or if you, you know there’s a whole host of other things that you can define conditionally to to run this, but basically all that the NPM package does is it scans your your commit message and will create a release based on that commit message. So if you wanna go hop into this repo. Kind of check out, but this looks like here. Maybe if you wanna zoom out just a little bit. Nick Woods 34:27 Umm. Sean Lawton 34:29 Great. OK, so you can see this is just a next JS app. Very just a basically like a Hello World app and you can see on the right we’ve got two releases that have been defined all via commit message and then. One of them is obviously a major release and then we have a patch release right? So if we hop into the. GitHub workflows. First, let’s look at the Docker build push. So I’ve got two workflows here. We’ve got Docker build push and we’ve got release right. So all this Docker build push workflow is doing is it’s running on push to the main branch it’s building the Docker image by running on Ubuntu latest GitHub host and runner. It’s checking out the code. It’s setting up the Docker build X with the Docker build X action. It’s logging into Docker with the Docker login action and then if you see we are using some credentials here that are stored inside of the secrets within GitHub Actions and those can be easily grabbed inside of our workflows via that syntax. And then finally, it’s building and pushing that image to the Docker hub. And you can see that it’s running the Docker file inside of the repo in that in that workflow,. So pretty simple, all it’s doing is pushing that and then if we look at the release example. This workflow is only going to run when it’s or once the Docker build push workflow, has completed and only on the main branch. And this is gonna create a new release only if the commit messages satisfy the. Semantic release run on the main branch, right? So if we look at the job, we’ve got some permissions modifications there to be able to write to GitHub and then we’ve got an action that checks out the code, an action that sets up node with a specific version. Then we’re globally installing PNPM. We’re creating a frozen lock file of all of our dependencies and then we’re creating a release with the MPX Semantic Release command and this, like I said, it’s gonna. It’s going to scan your commit messages and it’s only going to create a release if those commit messages satisfy the rules that are defined within the NPM semantic release package docs. So pretty cool example here. Kind of helps to automate things and you know keep everything very nice and clean. The next example that we’re going to look at here is cache management. So with a lot of legacy systems and even some current systems that we see, we have very long build times, sometimes upwards of 30 to 40 minutes. And sometimes these can be drastically reduced by caching things like dependencies or installing you know node or things like that. So we’re gonna kind of take a look here at a cache management example. We wanna hop into that repo there. Started to make you click around so much, but no. Nick Woods 38:19 He’s it’s right here. Sean Lawton 38:23 Yeah, alright. So as you can see, this is a super simple project. All we’ve got here is a read me and then a package JSON file with a bunch of dependencies inside of it. Umm, you know, obviously when you’re using Nodejs, you’re going to be installing tons of things and if you wanna hop into that GitHub workflow, we’ve got three different workflows here. We’ve got CI no cache. I cache and CI cache advance, so first the CI without cache. Super simple easy workflow that, UM literally all it’s doing is it’s running when we manually dispatch it. It’s running on an Ubuntu latest, you know, posted runner. Checking out the code, setting up node with a specific version and it’s just running a yarn install which is just installing the dependencies the next. Uh workflow, or the CI cache workflow,? Very similar actually. It’s basically the same thing, but instead of just installing the dependencies, it’s also caching the dependencies and these this cache is located in. If you wanna scroll up just a little bit, if you go to that Actions tab at the top. Nick Woods 39:50 Yep. Sean Lawton 39:52 Yeah, right there. And then we look at right on the left side under management, the cache is right there. So we can see we’ve got our dependencies cached and then also are notes setup cache. So if we look at the CI cache advance. That’s for that node. Cache is going to kind of come into into play here. So very similar caching the dependencies and then it’s caching node right? So this may not seem like a lot, but it can drastically reduce your build times. And if we if we go back to that Actions tab at the top, we can take a look at how long these took. So see I without cache took a minute and 15 seconds and then the advanced or the the basic CI cache took just under a minute and the CI cache advance only took 31 seconds. So 31 seconds versus a minute, 15 seconds. You know about a 44 second difference that may not seem like a lot, but when you have a project that grows larger and larger, it makes a big difference. And obviously that cache will be invalidated on any time that your your packages change, so you don’t have to worry about purging that cache manually or anything. So that’s a really cool example of something you can do, and then finally we’re going to dive into more of a complex example that kind of wraps everything that we’ve discussed here together. So there is a clean architecture starter template that I’ve used in the past. It’s by, I believe, his name is Jason Taylor. He has created this template. It’s got a full CI CD pipeline that leverages GitHub Actions. It’s got templated Azure bicep infrastructure as code files that get deployed via. A PowerShell script or the the the resource groups get deployed via a PowerShell script and then the actual infrastructure, gets deployed via GitHub actions and if we take a look at this repo here, we’ll kind of just look at it to start out with. So this is a clean architecture project. If we step into the source directory. You can see that we’ve got four projects here and this kind of goes back to that, that those onion or that onion example where we’ve got the core, which is the application project and the domain project. Now the application project has one project reference and that is only to the domain project and then you’ve got the outer layer which is the infrastructure and the web projects and those are two projects will have access to the inner core of the clean architecture pattern. So it’s just a really pretty organized way of setting up your.net projects. Or like I said, you can really use any programming language as it’s agnostic to that. So if you wanna take a look first at the scripts. We’ve got 3 scripts here. We’ve got checks set up and clean up the setup PowerShell script. All this is doing is literally setting up our uh Azure resource groups or three environments. We’ve got development, staging and production, and then it’s also creating some secrets to throw into our GitHub positor, and this is all automated. All you have to do is initialize and commit to a GitHub repo. Then you can run these PowerShell scripts and it will automatically create everything for you. It removes the massive headache of having to set everything up manually and you don’t have to worry about, you know, going into the Azure portal manually, clicking through everything you can also, you know, customize this if you don’t want three environments. You may only need two, or you may want four. You can add as many as you want. You just got to modify the scripts and then the. Did Bicep, files and that’s and then also the workflow files. So the other script that we’re gonna take a look at here is just the cleanup script and what this is doing is it’s removing all the resources from Azure. So if we do make a mistake or anything, we don’t have to worry about it. We can just run this clean up script and it will remove everything from Azure. All right, so next we’re going to take a look at that dot Azure directory and we’ll take a look at the Bicep, file in there. So this is where our infrastructure as code lies, right? It’s just a Bicep, file and then it’s defining 3 environments. Production, staging and development and then we’ve got a few different resources that are umm, being deployed or being defined inside of this Bicep, file. We’ve got like a SQL Server. We’ve got an app Service plan, an app service. We’ve got key vault, log analytics and all of these are being defined for all three uh environments that we have not super complex. Obviously these can get more more complex as you have a a larger project, but the good thing is you can create different Bicep, modules. You don’t have to have everything in this main dot Bicep, file. Alright, so next we’re gonna finally hop into the GitHub actions here. If you go into that, that GitHub and then inside of the workflows directory, we’ve got three different workflows in here. So first we’ll step into the build workflow. So from the top all this is doing is running on push to main branch. It’s ignoring some paths inside of our repo. And then we’ve also got a workflow called defined right here so that this template can be reused like we saw earlier in the presentation. And we’ve got some inputs that we can pass along with it. And then if we Scroll down a little bit, we’ve got one job called build running on Ubuntu, latest runner. Checking out the code caching the nugget packages with all with Actions we are installing net. Restoring the solution, building the solution, testing the solution, publishing the website, uploading the artifacts. And then it’s also using EF core, which is an RM for object relational mapping for our database. Uhitsinstalling.net EF tool it’s UM creating our uh migration bundles, zipping that up and then uploading that bundle artifact. So next, if we wanna step into the CI/CD dot YAML file. We can see that this is also running on push to the main branch, ignoring some paths. It’s setting some permissions and then it’s also. It’s got four jobs. It’s got the build job. It’s got deployed development, deployed staging and deploy production and you can see that it’s using both the build workflow and the deploy workflow inside of. Umm, inside of the jobs there. So it’s reusing those workflows so we don’t have to define the entire workflow inside of each file, which just makes it makes it much easier to read. And like I said, it’s don’t repeat yourself. Type type deal here. So finally we just want to take a look at that deploy file. This is running on workflow, call like we just saw in that CI/CD workflow, it’s changing some of the permissions around the first step that the first job that it’s gonna take is validating our Bicep, files right? So we don’t want to just immediately try to deploy our bicep, right? We wanna. We wanna validate and make sure everything is correct, so this step kind of handles that. You can see that it’s checking out the code, it’s logging into Azure with environment variables that are defined under that specific environment name. Or the name equals development. It is then using the arm deploy and then it’s running a preflight validation for for the that main dot Bicep, template. As you can see in the template tags there and then it’s also passing some parameters as well like we we add scene that that main dot Bicep, file is parameterized or templated in that way and then the final step that it’s taking here is the deploy step and you can see that it needs the validation step to complete before it runs and then it’s getting the specific environment name and it is going through the steps that it takes to similar to the validation it’s logging into Azure and then it’s deploying that infrastructure and then it’s also. Initializing the database and ultimately deploying the website to our app service. So this is just kind of like a really cool umm starter template that you can use for your larger enterprise applications. Umm, it’s it’s really maintainable and it’s great. It’s it’s basically all batteries included already is for you. So yeah, then if you wanna hop back to the presentation, that’s kind of the the mean potatoes here that we have for you for how you can use GitHub actions to enhance your (CI/CD) process and kind of take those old legacy applications and modernize them with more modern solutions, right? So for next steps we do have a free offer, free application modernization assessment and then we have also a free AI and copilot and envisioning session in in person or virtual of up to 100 people. So really want to thank everyone here for attending. We hope that you’ve gotten something out of this, whether it be you know whether you’re a newbie or you have you used it or use it daily. Hopefully you’ve gotten some out of this and we really appreciate your time today. So thank you very much. And then if we do have a survey for you to fill out, if you wouldn’t mind, it helps us out and helps us improve. So thank you very much for your time today. I really appreciate it.