---
title: 'CI/CD Pipeline Using GitHub Actions: Automate Software Delivery (for free)'
source: 'https://youtube.com/watch?v=p3W2XCD3smk'
video_id: 'p3W2XCD3smk'
date: 2026-08-02
duration_sec: 732
---

# CI/CD Pipeline Using GitHub Actions: Automate Software Delivery (for free)

> Source: [CI/CD Pipeline Using GitHub Actions: Automate Software Delivery (for free)](https://youtube.com/watch?v=p3W2XCD3smk)

## Summary

This video explains how to set up a CI/CD pipeline for free using GitHub Actions, covering both continuous integration (running tests) and continuous delivery (building and pushing Docker images). The presenter demonstrates with a .NET Core API that includes unit and integration tests, and shows how to push the built image to AWS ECR.

### Key Points

- **Introduction to CI/CD** [00:01] — CI (continuous integration) automatically runs unit and integration tests for each build, often on pull requests, to prevent broken code from merging. CD (continuous delivery) builds and packages the application, while continuous deployment also deploys to environments. Most companies prefer manual approval for production.
- **Project Overview** [01:57] — The example project is a simple .NET Core API that writes to a MySQL database, with unit and integration tests. The goal is to have GitHub Actions build a Docker image and push it to AWS ECR.
- **Application Architecture** [02:37] — The API has three layers: API layer (controllers, validation), service layer (business logic), and persistence layer (database). An SDK using Refit is used for integration tests to call the API.
- **Docker Multi-stage Build** [03:43] — A multi-stage Dockerfile is used: first stage uses the SDK image to restore and build, second stage uses the runtime image. Separating restore from build allows Docker to cache dependencies, speeding up builds.
- **Docker Compose Setup** [05:17] — Docker Compose defines a MySQL 8 database service and the API service, mapping port 5275 to 5200 to avoid clashes. This allows running the database and API locally for testing.
- **GitHub Actions Free Tier** [06:25] — GitHub Actions offers free minutes for Linux runners on public repositories, and a limited amount for private repositories. Windows runners cost 2x minutes, macOS 10x. This example uses Linux.
- **Workflow Configuration** [06:53] — The workflow is named 'build test and push', triggers on push, and has a single job 'build' running on ubuntu-latest. Steps include checkout, fetching tags, installing GitVersion, setting up .NET 7, restoring, building, running unit tests, spinning up Docker Compose, running integration tests, and pushing to ECR.
- **Running Unit Tests** [08:35] — Unit tests are run with 'dotnet test' filtered by category=unit, using Xunit traits. Test results are saved to a test results folder using the VSTest logger.
- **Running Integration Tests** [09:27] — Integration tests require a running database, so Docker Compose is used to start containers. A 30-second sleep ensures the API is ready. Tests are run with category=integration and an environment variable for the API URL.
- **Test Reporter** [10:23] — The Test Reporter action from the Marketplace provides a nice UI showing test results (pass/fail/skipped) and works with .NET, Dart, Flutter, Java, and JavaScript.
- **Continuous Delivery to AWS ECR** [11:01] — The Docker image is pushed to AWS ECR using GitHub Secrets for credentials. The step only runs on the main branch to avoid pushing from feature branches.

### Conclusion

GitHub Actions provides a free, integrated CI/CD solution for GitHub-hosted projects, enabling automated testing and container image delivery. The video demonstrates a complete pipeline from code push to Docker image upload, with test reporting and branch-based deployment control.

## Transcript

so in today's video we're going to look at cicd pipelines and in particular how we can create them for free using GitHub actions CI CD is not something I've going to quickly explain what it is and why we use it so CI stands for
continuous integration and it's the process of automatically running all of your unit tests and integration tests for each of your builds now you don't integration tests running on every single commit it can just be whenever
you create a pull request your test run automatically and at least this way if the tests fail you can stop that code being merged into develop or Master you your unit tests on your machine before you raise your pull request but having
server is a good quality control to have in place and it also prevents the running on your machine and not anyone else's in the past I've used tools such as teamcity and Jenkins to run my CI pipelines but more and more teams are
already on GitHub then it's a bit of a no-brainer to run your tests on there as well and it will also save money on licensing and server costs now CD can continuous deployment they're both quite
continuous delivery is really about building and packaging up your on the server but it doesn't actually include the deployment of your application continuous deployment on the other hand also covers the deployment of
environment most companies don't like having applications going straight to production without any manual intervention it's quite typical to have the dev and QA environments but when it comes to production generally you want
some manual controls in place in the past I've always used octopus deploy to different environments but it's actually possible to do that in GitHub actions as functionality of GitHub actions I've created a very simple.net core API that
writes to a mySQL database this project include unit and integration tests and those as well as show off the results in a nice format for the continuous to have GitHub actions build out a Docker image and have it push it to AWS
ECR for me I'm not going to cover how to do any of those manual approval a future video all the code that you're going to see in this video is available to my paid newsletter subscribers my newsletter is otherwise free at the
channel then that's the best way to do it I'll leave a link in the description so you can check it out so the dotnet core API that I've put together for this project is a very simple library application so think something similar
to Goodreads so this application is really made up of three layers we have our API layout which has all the controllers all the endpoints and handles things like validation we then have the service layer that handles all
our persistence layout which is saving everything to the database I also have an SDK which I've written using a great.net core package called refit and this is what I'm then using in my integration test to be able to call my
API so I've got some endpoints for adding authors to the database as well as getting them either singularly or as a paged result I then have another controller that lets you add books as well as retrieve them in a similar way
got unit tests I haven't done a complete set but there's unit tests for both the service layer and then for the that show that you can create an author and retrieve it as well as creating a
integration tests aren't using any of the API code they're just relying on the SDK so in order to be able to run the integration tests in GitHub actions we the database and the way we do this is with Docker so because I've built my
application with net core I've put together a multi-stage Docker file to be able to build and run my application now there's probably other ways depending on application and GitHub actions but I'd recommend if you're going to be
deploying your application using Docker anyway that you use that Docker image for testing your application so there's a few things that make up a net or Docker file we have first we're going to use the SDK image from Microsoft so this
application we're then going to copy across all of our project files and this against them now the reason that we separate this instead of just copying across everything is because.net restore is quite a lengthy process you've got to
download all the new get packages and by separating it out we can basically have in Docker so provided you don't change any of these project files by adding in any additional dependencies it means that when you run.net restore it
run it again even if you change the other files in your application once.net restore is done we then copy across all the other files and then run.net publish in release mode to be able to build our application now of course we don't want
part of our Docker image because it's going to make our Docker image quite large we're then going to get the.net runtime image and we're going to copy built in the other container and you can see here I'm exposing Port 5275 which
we're then going to use later on to call our API so as I mentioned earlier to be need a database running in the back end so I'm using MySQL for this and I'm just using the standard MySQL image so you can see here in my Docker compose file I
have a database service set up using MySQL 8 and I have some very basic and not very secure passwords set up here just for use for testing and then I'll have our API set up and you can see here
files in the same folder and then we're tagging this image with GitHub actionsdemo.api and then version and I'll cover where that version is coming from in a bit so you can see here I've got the port set to 5275 by then mapping
that 5200 in the docker compose file and this is so you can run the docker compose file with the database and not worry about any port clashes when you run the API locally on your machine so if we run Docker compose up we can see
this is going to spin up our mySQL database as well as our API as well we be able to call IPI and make sure that everything works for the paid project I've also included this Postman collection as part of it so you can
easily test out the API so that's how this API works next we're going to have see how we can put everything together so we can run our tests in GitHub so GitHub actions does have a very generous free tier you can run the standard Linux
Runners for free if you've got a public repository for private repositories you you can use for free this is only for the Linux Runners if you opt for the windows Runners then you're going to use twice as many minutes and if you opt for
use 10 times the amount so you're going to see the amount of three minutes you have go down pretty quickly so for this example I can use Linux as.net core as on what you're using so the first thing we need to set up is a name so I've just
called this build test and push we then specify when we want this to run so just for this example I'm doing on push so every time I push something to my repository it's going to run this test but you could set it up to just do it on
pull request or on merge for example and you can even specify particular branches that you want it to run on now we need to set up our jobs for this example I'm just setting up one job called build so you can create multiple jobs in GitHub
actions but it gets a bit complicated you can't just use variables and data that you've had in one job to be used into the next job you have to use the artifacts and upload them and download them between each of the jobs again I'll
but for now it's easier just to keep everything in one job next we specify where our job runs so this case I'm just using Ubuntu latest again this is the cheapest option if you're using GitHub actions so first we need to check out
our code now GitHub obviously comes with a standard action to be able to do this part of this setup I want to get the semantic version of my application to be able to tag my Docker image and to do that I'm using Git Version but I found
Git Version doesn't actually work unless you go and grab the tags using git fetch fetch an unshallow copy of my code I can then install Git Version and then run Git Version execute to be able to get the semantic version of my code next
we're going to set up.net as I'm using.net and here we specify the version so I'm using.net7 we then need to run the same commands that we would on our machine so in this case we run.net restore to build our
dependencies and net build to build our project so now we've got our.net code built on the GitHub Runner so next I'm going to run my unit tests so I'm running.net test and I've got a filter here with a category equals unit now I
can do this because I'm using X unit and I've set up a trait to specify the category so when I run my unit tests this is going to produce a test results file and this is because I've got this vs test logger set up in my project now
I've set this up so it will put all the test results into a test results folder inside the test project and then later I'm going to use the test reporter to be able to show these test results in GitHub so I I have to create a test
results folder in my root project and copy across the tests results now the reason I'm doing this is because when I come to run my integration tests it's going to overwrite the unit test results for some reason when you use a filter it
produces the test result file which is a bit annoying so now that we've run all integration tests now to be able to do this we need to spin up a Docker container and we can do that using our Docker compose file now you can see here
specifying that we should always build our project and I've got the minus D's can see here I'm specifying a version earlier in our Docker compose file and this is going to get the nuget version
and this is going to make sure that when we build our application in Docker with the correct version now in The Next Step we're just going to sleep for 30 do this you could call the API to see whether it's up and running but this is
reason we have to do this because if we jump on onto running our integration containers might not be up yet and it will just fail now for our integration tests we're just running.net test again because they're just X unit tests and
this time we're filtering by category integration and here I'm specifying the that it knows to call the API that's once that's run we're going to copy across the integration test results into
our test results folder next I'm using this test reporter action from the GitHub actions Marketplace this gives you a nice view of all of the tests from your application and whether they pass failed or been skipped and how long each
about this test reporter GitHub action is it also works with lots of different languages it works obviously with net we've got X unit and unit and Ms test but also works with dart flutter Java and JavaScript so if you're using any of
those you can get a nice report from your test results and you can see here we've got if success or failure which basically just means this is always integration tests passed or failed now for the continuous delivery part of this
workflow I'm going to push the docker image that we previously created up to AWS ECR now I've already gone ahead and created an AWS ECR repository and I've key and a secret key now to make sure that these Keys can't be seen I'm using
the GitHub secrets that stores them encrypted in your repository and then they don't appear when you build now I've created another if statement here which means that this step is only going to run if you're running on the main
branch if we run it on develop or on a pull request Branch it's not going to push anything up to AWS ECR if we run all this on GitHub actions you can see it all goes through and passes we've then got a nice test report that shows
our unit tests on our integration test results and finally if we look on AWS you can see here that the image is uploaded successfully now if you want to project if you become a paid subscriber of my newsletter you'll get complete
to all of my future videos and I'm also planning on releasing a few courses in generous discounts for all of my paid subscribers thank you for watching this video I hope it's been helpful and I'll see you in the next video
