This repository demonstrates how to set up a CI/CD pipeline for a Razor Pages Movie application using GitHub Actions. The pipeline includes building, testing, and deploying the application to Azure Container Apps.
The Razor Pages Movie application is a simple movie list application that allows users to view, create, edit, and delete movies. The application is built using the following technologies:
- Frontend: Razor Pages, HTML, CSS, Bootstrap
- Backend: ASP.NET Core Razor Pages, Entity Framework Core
- Database: Azure SQL Or SQL Server Database
- Testing: xUnit, Selenium
- Deployment: Azure Container Apps via OIDC (OpenID Connect)
- Infrastructure: Terraform (IaC)
- CI/CD: GitHub Actions
- Monitoring: Application Insights on Azure Portal
- GitHub Advanced Security: CodeQL Analysis, secret scanning, Dependabot alerts, GitHub Copilot Auto-Fix suggestions on PRs
To run the Razor Pages Movie application locally using Docker Compose, follow these steps:
- Ensure you have Docker and Docker Compose installed on your machine.
- Navigate to the root directory of your project where the
docker-compose.yml
file is located. - Run the following command to start the application:
docker compose up
This command will start both the SQL Server and the web application containers.
To run the Razor Pages Movie application in GitHub Codespaces with the default .devcontainer setup, follow these steps:
Open the repository in GitHub Codespaces. The .devcontainer setup will automatically start the application on startup on port 80.
The landing page will prompt you to login. By default, there are two main user logins for demonstration purposes:
- Admin: Username:
admin
, Password:password
- User: Username:
user
, Password:password
The web application will be accessible at: http://localhost
Disclaimer - expand to read
The application is not yet fully functional and is still under development.
The default behavior is that the application will run on http://localhost with SSL/TLS certificate validation disabled when connecting to the SQL Server. This is achieved by adding the TrustServerCertificate
parameter to the connection string in the docker-compose.yml
file. This allows the application to connect to the SQL Server without validating the SSL/TLS certificate.
The CI/CD pipeline is defined using GitHub Actions workflows and Terraform for infrastructure as code. The main workflows are:
- π CI Workflow: Builds and tests the application.
- π CD Workflow: Deploys the application to Azure and runs UI tests.
- π§Ή Housekeeping Workflow: Cleans up resources after testing.
Continuous Integration ensures that every change to the codebase is automatically built and tested. This helps catch issues early and maintain code quality. The CI workflow is triggered on push and pull request events and performs the following steps:
- π₯ Checkout Code: Checks out the repository code.
- βοΈ Set up .NET: Sets up the .NET environment.
- π¦ Restore Dependencies: Restores the project dependencies.
- ποΈ Build Project: Builds the project.
- π CodeQL Analysis: Performs CodeQL analysis on the codebase to identify potential security vulnerabilities.
- π§ͺ Run Tests: Runs unit tests and uploads test results.
β¨ Interactive Diagram Below! β¨
π Click to expand and view the CI Workflow Steps chart
graph TD
A[π₯ Checkout Code<br>Clone the repository to the runner environment] --> B[π Initialize CodeQL<br>Set up CodeQL for security analysis]
B --> C[βοΈ Set up .NET<br>Install .NET SDK and runtime]
C --> D[π¦ Cache NuGet Packages<br>Cache dependencies to speed up the build process]
D --> E[π¦ Restore Dependencies<br>Restore NuGet packages required for the project]
E --> F[ποΈ Build Project<br>Compile the project and generate binaries]
F --> G[π Publish Project<br>Prepare the project for deployment]
G --> H[β¬οΈ Upload Published App<br>Upload the compiled project for further steps]
H --> I[π Perform CodeQL Analysis<br>Analyze the codebase for security vulnerabilities]
I --> J[π Split Tests<br>Divide tests into smaller groups for parallel execution]
J --> K1[π§ͺ Run Unit Tests - Group 1<br>Run unit tests for the first group]
J --> K2[π§ͺ Run Unit Tests - Group 2<br>Run unit tests for the second group]
J --> K3[π§ͺ Run Unit Tests - Group 3<br>Run unit tests for the third group]
K1 --> L[π Publish Test Results<br>Publish the results of all unit tests]
K2 --> L
K3 --> L
L --> M[π Upload Code Coverage Report<br>Generate and upload the code coverage report]
subgraph Pull Request Process
N[Create Pull Request<br>Developer creates a pull request] --> O[Run CI Workflow<br>CI workflow is triggered]
O --> P[CodeQL Analysis<br>Analyze the codebase for security vulnerabilities]
O --> Q[Build Project<br>Compile the project and generate binaries]
O --> R[Run Unit Tests<br>Run all unit tests]
P --> S{CodeQL Analysis Passes?}
S -- Yes --> T[Proceed to Unit Tests]
S -- No --> U[Fail PR<br>CodeQL analysis failed]
Q --> V{Build Passes?}
V -- Yes --> W[Proceed to Unit Tests]
V -- No --> X[Fail PR<br>Build failed]
R --> Y{Unit Tests Pass?}
Y -- Yes --> Z[All Checks Passed<br>Ready for review and merge]
Y -- No --> AA[Fail PR<br>Unit tests failed]
end
subgraph Merge Process
AB[Review PR<br>Reviewers review the pull request] --> AC{All Reviews Approved?}
AC -- Yes --> AD[Merge PR<br>Merge the pull request into the main branch]
AC -- No --> AE[Request Changes<br>Developer makes changes and updates the PR]
end
subgraph Repository Rulesets
AF[Status Checks<br>Ensure all status checks pass before merging]
AG[Branch Protection<br>Enforce Repository Branch Rulesets]
AH[Require Reviews<br>Require at least one review before merging]
AI[Restrict Merge<br>Restrict who can merge pull requests]
end
Z --> AB
AD --> AF
AD --> AG
AD --> AH
AD --> AI
Continuous Delivery automatically deploys the application to Azure Container Apps whenever changes are pushed to the main branch. This ensures that the latest version of the application is always available in the staging and production environments. The CD workflow includes:
- π¦ Build and Deploy Container Image: Builds the container image and deploys it to a container registry.
- π₯ Checkout Code: Checks out the repository code.
- π Az CLI Login via OIDC: Logs in to Azure CLI using OIDC.
- π Deploy the Azure App - Including DB Migrations [STAGING ENVIRONMENT]: Deploys the application to the staging environment using Terraform.
- π§ͺ Run UI Automated Selenium Tests: Runs UI tests using Selenium.
- π Generate Workflow Telemetry: Generates heat map and performance data.
- π Create QA Ticket: Creates a QA ticket to notify that the staging environment is ready for testing.
- π Deploy the Azure App - Including DB Migrations [PRODUCTION ENVIRONMENT]: Deploys the application to the production environment using Terraform.
- π Capture Terraform Output: Captures the Terraform output.
- π·οΈ Create GitHub Release: Creates a GitHub release with the deployment details.
β¨ Interactive Diagram Below! β¨
π Click to expand and view the CD Workflow Steps chart
graph TD
subgraph Build and Push Docker Image
A[π³ Build Docker Image<br>Build the Docker image]
A --> B[π€ Push Docker Image<br>Push the Docker image to GHCR]
end
subgraph Deploy to Staging
D[π₯ Checkout Code<br>Clone the repository to the runner environment] --> E[π Az CLI Login via OIDC<br>Authenticate with Azure]
E --> F[π Deploy the Azure App - Including DB Migrations]
F --> G[π Capture deployment outputs]
G --> H[π Generate URL at Commit Hash to IaC Staging Files]
end
subgraph Functional UI Tests
H --> I[π§ͺ Run UI Tests<br>Run UI Automated Selenium Tests]
I --> Q1[π Run functional UI tests on Chrome]
I --> Q2[π Run functional UI tests on Firefox]
I --> Q3[π Run functional UI tests on Edge]
I --> Q4[π Run functional UI tests on Chromium]
end
subgraph Post-Functional tests Steps
I --> J[π Generate Telemetry<br>* Runner Utilization Metrics<br>* CPU heat map<br>* Memory usage]
J --> K[π Create QA Ticket<br>Create QA Ticket for testing]
end
subgraph Deploy to Production
K --> L[π Deploy to Production Azure App]
L --> M[π Capture Terraform Outputs]
M --> N{π Check if Revision Exists}
N --> O{π Deploy new revision with smaller traffic <=30%}
O --> P[π·οΈ Create a GitHub release for the new deployment]
end
B --> F
B --> L
This deployment strategy is orchestrated with the Terraform scripts located in the terraform
folder.
flowchart TD
subgraph Staging Deployment
A1[π Start] --> B1[ποΈ Create Staging Database]
B1 --> C1[π¦ Deploy Staging Container App with Single Revision]
C1 --> D1[π Set Traffic to 100% for Latest Revision]
D1 --> E1[π End]
C1 -->|Failure| F1[β©οΈ Rollback to Previous State]
end
subgraph Production Deployment
A2[π Start] --> B2[π Check Existing Container App]
B2 --> C2{π Existing Revision?}
C2 -->|βοΈ Yes| D2[π Create New Revision with Canary Deployment]
C2 -->|β No| E2[π¦ Create Production Container App]
D2 --> F2[π Set Traffic Split for Canary Deployment]
F2 --> G2[π Monitor and Validate New Revision]
G2 --> H2{β
Valid?}
H2 -->|βοΈ Yes| I2[π Promote New Revision to Production]
H2 -->|β No| J2[β©οΈ Rollback to Previous Revision]
E2 --> I2
I2 --> K2[π End]
end
Database deployments are handled as part of the application deployment process. During the deployment, database migrations are applied to ensure the database schema is up-to-date. If the deployment fails, the changes are rolled back to the previous state to maintain database integrity.
flowchart TD
subgraph Database Deployment
A[π Start] --> B[π Check Database State]
B --> C{π Migrations Pending?}
C -->|βοΈ Yes| D[π Apply Pending Migrations]
C -->|β No| E[π End]
D --> F[π Monitor Migration Progress]
F --> G{β
Successful?}
G -->|βοΈ Yes| H[π End]
G -->|β No| I[β©οΈ Rollback Migration]
I --> E
E --> H
end