Introduction
GitHub Actions enables automating processes like integration and deployment through workflows in GitHub. A workflow is a collection of one or more jobs that are executed in response to some trigger (automated or manual) or on scheduled intervals. In this article, we will create a simple workflow to build, test and deploy ASP.NET Core web app to Azure App Service.
Typically, whenever code is merged into a master (or main) branch in GitHub, we would like to ensure that it builds without any error and all the unit tests pass. These steps will constitute Continuous Integration (CI) part of the workflow. After build and tests are successful, we would like to deploy the code to Azure App Service so that it is available for QA and eventually to end users. This comprises our Continuous Deployment (CD) part of the workflow.
Setup
Create a new repository in GitHub and note the remote URL of the repo. We will use this URL to push our code from local git repo to GitHub.
Create a new folder called github-actions-demo where the app and the test project will be stored on your local machine. Create a new solution file inside this folder by executing the following dotnet CLI command
dotnet new sln
Create a new ASP.NET MVC Core Web App by executing the following dotnet CLI command in the context of the folder created in the previous step.
dotnet new mvc -o github-actions-demo-app
Add the project to the solution by executing the following dotnet CLI command
dotnet sln add github-actions-demo-app
Switch to the project directory (github-actions-demo-app) and build the project
dotnet build
Run the app using the following CLI command
dotnet run
It should display the application home page in the browser as shown in the screenshot below:-
Switch back to the root project folder and add a new MSTests Project by running the following dotnet CLI command
dotnet new mstest -o github-actions-demo-app-tests
Add the test project to the solution
dotnet sln add github-actions-demo-app-tests
Add reference of the ASP.NET project to the test project by switching to the test project directory in console and executing the following dotnet CLI command
dotnet add reference ../github-actions-demo-app/github-actions-demo-app.csproj
Open the test project in VS Code. For the purpose of this article we will add a dummy test as follows in UnitTest1.cs file
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Assert.IsTrue(true);
}
}
Build the test project and execute tests using the following CLI command. Note that the following command also works in context of the root project folder that contains the solution file
dotnet test
Adding projects to local git repo
Add gitignore file to the root project directory (github-actions-demo) by executing the following CLI command
dotnet new gitignore
Initialize local git repo
git init
Stage the changes
git add .
Commit changes to local git repo
git commit -m "Initial commit"
Add URL of the remote GitHub repository. Replace <repo_url> with the URL of the repository that you created in one of the previous steps
git remote add origin <repo_url>
Push code to GitHub
git push origin master
Navigate to the GitHub repo in your browser to validate the code is pushed successfully.
Continuous Integration
You can create a GitHub action workflow by navigating to the Action tab on your repository page in the browser. Alternatively, you can also write workflow declaratively inside your code editor. We will go with the second approach.
Add a new folder inside the root project directory and name it .github. Create a subfolder inside .github folder called workflows. Inside the workflows folder add a new file named app-build-deploy-workflow.yml. The folder structure looks like the screenshot below (from VS Code):-
Add following code to app-build-deploy-workflow.yml
name: build-deploy-azure-app
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Install dotnet
uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.x
- name: Restore Nuget packages
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build
- name: Publish
run: dotnet publish github-actions-demo-app/github-actions-demo-app.csproj -c Release -o website
- name: Upload Artifact
uses: actions/upload-artifact@v2
with:
name: app
path: website/**
if-no-files-found: error
- name – Name of the workflow
- on - Defines the trigger condition – only run the workflow when the code is pushed to the master branch
- runs-on – The GitHub managed VM image on which the CI job would be executed
- Checkout branch – Checks out the master branch to enable the job to read the code
- Install dotnet – Installs dotnet CLI that will be used to build, test and publish the projects. Since my projects target .NET 6, I have mentioned the same as the .NET SDK version under dotnet-verison. Please change the value as per the version that your project targets.
- Restore Nuget packages – Restore nuget package dependencies
- Build – Build the project. Since the dependencies have already been installed in the previous step, we need not attempt to restore them again
- Test – Execute tests in all the test projects present in the solution
- Publish - Publish the web app in Release mode to directory named "website"
- Upload Artifact - Store the output published in the previous step so that it can be used in subsequent job while deployment. If there is no output from the previous step, throw an error.
Stage and commit the changes and push them to GitHub using the git commands mentioned in the previous steps. As soon as you perform push to master branch, the workflow is triggered. You can watch the execution logs of the workflow under the Actions tab on your repository page. After successful execution of the workflow, an artifact is generated that contains the deployable package that can be consumed by CD process to deploy the app to Azure App Service.
Azure Setup
Create a new resource group and an Azure Web App targeting appropriate .NET version and OS.
Create new Azure service principal by navigating to Azure Active Directory -> App Registrations -> New registration and filling in the required details. Once the service principal is created, note the application id. On the left menu, click on Certificates & Secrets and generate a new secret. Note the application secret. We will use the id and secret while configuring the deployment job for workflow.
Navigate to the Azure web app, click on the Access Control (IAM) menu on the left. Click on Add role assignment and select Contributor role and click Next. Clik on Select Members, search and add the service principal name created in the previous step and click Review + assign. This will assign Contribute permission to the service principal to the Azure Web app to be able to perform deployments.
Also note the tenant ID and subscription ID of your Azure tenant and subscription as they would be needed along with the service principal credentials to establish connection from our workflow to Azure.
Continuous Deployment
Let’s first store the credentials and Azure ids as repository secrets. Navigate to the GitHub repository settings and click on Secrets on the left menu. Add a new secret called AZURE_CREDENTIALS. The value of the secret is a JSON object in the following format (Replace <GUID> with corresponding values from your Azure subscription).
Update the app-build-deploy-workflow.yml file in the code editor. Add a "deploy" job after the "build" job as follows (below snippet just shows a particular section of the workflow file. The entire yml file text is mentioned towards the end of this article).
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download Artifact
uses: actions/download-artifact@v2
with:
name: app
path: app
- name: Login to Azure
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Deploy to Azure
uses: azure/webapps-deploy@v2
with:
app-name: github-actions-demo-1
package: app
- name: Logout from Azure
run: az logout
- needs – Specifies that the deploy job is dependant on successful execution of the build job
- runs-on – The GitHub managed VM image on which the CD job would be executed
- Download Artifact – Downloads the artifact that was uploaded by the the build job
- Login to Azure – Log in to Azure with the credentials stored in the repository secret. Note that repository secrets can be accessed by following syntax -
- ${{ secrets.<secret_name> }}
- Deploy to Azure – Deploy the app artifact contents to Azure web app. github-actions-demo-1 is the name of my Azure web app. Replace this with the name you have chosen for your Azure web app.
- Logout from Azure –Logs out from Azure
Complete Workflow YAML File
name: build-deploy-azure-app
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Install dotnet
uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.x
- name: Restore Nuget packages
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build
- name: Publish
run: dotnet publish github-actions-demo-app/github-actions-demo-app.csproj -c Release -o website
- name: Upload Artifact
uses: actions/upload-artifact@v2
with:
name: app
path: website/**
if-no-files-found: error
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download Artifact
uses: actions/download-artifact@v2
with:
name: app
path: app
- name: Login to Azure
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Deploy to Azure
uses: azure/webapps-deploy@v2
with:
app-name: github-actions-demo-1
package: app
- name: Logout from Azure
run: az logout
Final Commit and Test
Stage and commit the changes and push them to GitHub using the git commands mentioned in the previous steps. As soon as you perform push to master branch, the workflow is triggered.
After successful execution of the workflow, you should be able to see the app under Azure web app URL
Let's make a small change to the Welcome text. Open the web app in code editor and update "Welcome" in Views -> Home -> Index.cshtml to "Welcome to DevOps !!"
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome to DevOps !!</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
Save the file, stage, commit and push the changes to GitHub repo's master branch. After successful workflow execution the code changes are visible on the deployed Azure web app. Refresh the browser where you have the Azure web app open and you should be able to see the changes.
References