Tutorial: Setting up Azure DevOps Infrastructure and Pipelines for a Full-Stack .NET 8 Application

Table Of Content

Table of Contents

  • 1. Project Setup and Structure
  • 2. Infrastructure and Environments
  • 3. Pipeline Requirements
  • 4. Testing and Quality Gates
  • 5. Additional Tools or Integrations
  • 6. Security and Compliance
  • 7. Developer Experience

Author: Sami Belhadj

Connect on LinkedIn

Setting up Azure DevOps Infrastructure and Pipelines

Introduction

Welcome to our comprehensive tutorial on setting up Azure DevOps Infrastructure and CI/CD pipelines for a full-stack .NET 8 application!

In today's fast-paced development landscape, delivering high-quality software quickly and reliably is more important than ever. Whether you're working on a new product, upgrading an existing system, or managing a large-scale application, having a well-structured DevOps pipeline can make all the difference. That's where Azure DevOps comes in—a powerful platform that brings together development, operations, and quality assurance in one seamless workflow.

Why This Tutorial?

This tutorial is designed to be your go-to guide for mastering Azure DevOps and applying it to a full-stack application built with the latest technologies—C# .NET 8, Entity Framework Core, SQL Server, and Angular. You’ll learn how to create a robust, scalable infrastructure that supports automated testing, security checks, and continuous delivery across all your environments.

Whether you're a seasoned DevOps engineer looking to refine your skills or a developer stepping into the world of continuous integration and deployment, this tutorial will provide the practical insights, tools, and strategies you need to succeed.

What You’ll Learn

In this tutorial, we'll walk you through every step of setting up a complete DevOps pipeline, covering:

  • Project Setup and Structure: Learn how to organize your backend, frontend, and infrastructure repositories for modular, scalable development.
  • Infrastructure and Environments: Discover how to configure your on-premise OpenShift platform to host multiple environments—from Development to Production—ensuring consistent deployment across the board.
  • Pipeline Requirements: Set up automated Azure DevOps pipelines with YAML to manage build, test, and deployment processes, integrating tools like SonarQube, Checkmarx, and Nexus.
  • Testing and Quality Gates: Implement a comprehensive testing strategy with unit tests, integration tests, static code analysis, and security scans to enforce quality and compliance.
  • Additional Tools and Integrations: Explore how to enhance your pipelines with tools like Xray for manual testing, UiPath for automated testing, and Grafana and ELK Stack for monitoring and logging.
  • Security and Compliance: Leverage Azure Key Vault, Checkmarx, SonarQube, and OWASP ZAP to secure your application and ensure compliance with industry standards.
  • Developer Experience: Optimize your development workflow with tools, scripts, and best practices for Visual Studio 2022 and VS Code, enhancing productivity and collaboration.

Why Azure DevOps?

Azure DevOps provides a unified platform that integrates with a wide range of tools, frameworks, and environments, making it the perfect choice for managing complex, modern applications. With Azure DevOps, you get a complete toolkit for source control, pipeline automation, testing, monitoring, and security—all in one place.

By mastering Azure DevOps, you can automate repetitive tasks, reduce manual errors, and deliver software faster and more reliably. You will be empowered to focus on what matters most—building great applications that delight your users.

Who Should Follow This Tutorial?

  • DevOps Engineers: Looking to refine their CI/CD pipeline skills with Azure DevOps and learn advanced strategies for managing deployments and testing.
  • Developers: Seeking to understand how DevOps practices enhance software delivery and quality, and how to set up pipelines for full-stack applications.
  • IT Managers: Interested in improving the efficiency and reliability of software delivery processes.
  • Security Professionals: Aiming to integrate security checks and compliance policies into the development lifecycle.

Get Started Today!

By the end of this tutorial, you'll have a fully operational Azure DevOps pipeline tailored to a full-stack .NET 8 application, complete with best practices for security, testing, monitoring, and developer experience. Whether you're building new applications or optimizing existing ones, this guide will equip you with the knowledge and tools to excel in your DevOps journey.

So, let's dive in and get started with creating a world-class DevOps environment for "Defi-Central"!

Project Setup and Structure for Defi-Central

Overview: "Defi-Central" is a full-stack application consisting of multiple components:

  • Backend API built with C# .NET 8.
  • Frontend developed using Angular.
  • Database managed with Entity Framework Core (EF Core) and SQL Server.
  • Infrastructure to handle deployment and environment configuration.

To efficiently manage these components, we will use multiple repositories: one for each main component and one for infrastructure. This separation ensures that each team can work independently while maintaining a clean and organized codebase.

Repository Structure

We will create three separate repositories:

  • Backend Repository (defi-central-backend): Contains the .NET 8 Web API and related backend logic.
  • Frontend Repository (defi-central-frontend): Contains the Angular front-end code and assets.
  • Infrastructure Repository (defi-central-infra): Contains the Infrastructure as Code (IaC) configurations and deployment scripts.

Detailed Structure of Each Repository

1. Backend Repository (defi-central-backend)

The backend repository contains the core logic of the application, which includes the .NET 8 Web API, EF Core for database access, and unit and integration tests.

defi-central-backend/
      ├── src/
      │   ├── DefiCentral.Api/                   # Main Web API project
      │   │   ├── Controllers/                   # API Controllers
      │   │   ├── Models/                        # Data models and DTOs
      │   │   ├── Services/                      # Business logic and services
      │   │   ├── Startup.cs                     # Application startup configuration
      │   │   └── Program.cs                     # Main entry point of the application
      │   └── DefiCentral.Data/                  # Data access layer using EF Core
      │       ├── Migrations/                    # EF Core migrations
      │       ├── Models/                        # Database models (e.g., Entities)
      │       └── DefiCentralDbContext.cs        # EF Core DbContext configuration
      ├── tests/
      │   ├── DefiCentral.UnitTests/             # Unit tests for API and services
      │   └── DefiCentral.IntegrationTests/      # Integration tests with a test database
      ├── scripts/
      │   ├── init-db.ps1                        # Script for local database initialization
      │   └── run-migrations.ps1                 # Script for applying EF Core migrations
      └── .azure-pipelines/
        └── backend-ci-cd.yml                  # Azure Pipeline definition for backend
            

2. Frontend Repository (defi-central-frontend)

The frontend repository manages the Angular codebase and assets required for the client-side of "Defi-Central."

defi-central-frontend/
      ├── src/
      │   └── defi-central-angular/              # Main Angular application
      │       ├── src/                           # Angular source files
      │       │   ├── app/                       # Main application module
      │       │   │   ├── components/            # Reusable components
      │       │   │   ├── services/              # Angular services for API calls
      │       │   │   └── app.module.ts          # Root module of the Angular app
      │       │   ├── assets/                    # Static assets (images, icons, etc.)
      │       │   ├── environments/              # Environment-specific configurations
      │       │   └── index.html                 # Entry HTML file
      │       ├── angular.json                   # Angular CLI configuration
      │       └── package.json                   # NPM dependencies
      ├── tests/
      │   ├── unit/                              # Unit tests for Angular components
      │   └── e2e/                               # End-to-End tests
      ├── scripts/
      │   └── setup-env.sh                       # Script to set up local environment
      └── .azure-pipelines/
        └── frontend-ci-cd.yml                 # Azure Pipeline definition for frontend
            

3. Infrastructure Repository (defi-central-infra)

The infrastructure repository holds all the configurations and scripts necessary to deploy the application to the target environment (OpenShift).

defi-central-infra/
      ├── IaC/
      │   └── OpenShift/                         # OpenShift configurations
      │       ├── deployment.yaml                # Deployment definitions for backend and frontend
      │       ├── service.yaml                   # Service definitions for networking
      │       └── ingress.yaml                   # Ingress configurations for routing
      ├── scripts/
      │   ├── deploy-openshift.sh                # Script for deploying to OpenShift
      │   └── setup-env.sh                       # Environment setup script
      └── .azure-pipelines/
        └── infra-ci-cd.yml                    # Azure Pipeline definition for infrastructure
            

Why This Structure?

  • Separation of Concerns: Splitting the backend, frontend, and infrastructure codebases allows teams to work independently, focus on specific domains, and reduce merge conflicts.
  • Modular and Scalable: Each repository is focused on a specific part of the application, making it easier to manage, scale, and deploy.
  • Ease of CI/CD Integration: Each repository contains its own pipeline definition, ensuring that the CI/CD processes are tailored to the needs of the specific component.
  • Facilitates DevOps Practices: Scripts are included to automate common tasks, enabling continuous integration and deployment.

Infrastructure and Environments for Defi-Central

Overview: For "Defi-Central", we will set up multiple environments to support the development, testing, and production deployment of the application. These environments will be hosted on-premise within your organization's OpenShift platform. Each environment serves a distinct purpose and has unique configuration requirements to ensure smooth and secure deployment across the entire software development lifecycle (SDLC).

Environments Setup

The application will be deployed across four environments:

  • DEV (Z): The development environment where developers integrate their code and perform initial testing. This environment is meant for rapid changes and experimentation.
  • Integration (I): The integration environment is used for combined testing across different modules and services. It is the staging ground for features before moving them to UAT. This environment often includes automated testing and static code analysis.
  • UAT (Y): The User Acceptance Testing environment where stakeholders and end-users validate the application's functionality against business requirements. It mirrors the production environment closely.
  • PROD (X): The production environment where the final, stable release of the application is deployed for end-users. This environment has the highest level of security, performance, and availability.

Hosting and Deployment Targets

The "Defi-Central" application will be hosted on an on-premise OpenShift platform. Each component of the application (backend API, frontend, and database) will be deployed as separate services within the OpenShift environment.

Key Deployment Components:

  • Backend API Service (C# .NET 8): Exposed as a RESTful API service.
  • Frontend Service (Angular): Served as a static site or hosted through a containerized web server (e.g., Nginx).
  • SQL Server Database: Deployed as a service within OpenShift, managed with EF Core migrations.

Resource Group Details

In the context of an on-premise OpenShift platform, we will not use Azure Resource Groups, but we will create and manage namespaces within OpenShift for organizing resources in each environment.

Namespace Configuration:

  • Create separate namespaces for each environment: defi-central-dev, defi-central-integration, defi-central-uat, and defi-central-prod.
  • Each namespace will isolate its respective environment's resources, such as deployments, services, secrets, and ingress configurations.

Deployment Configuration on OpenShift

To deploy "Defi-Central" on OpenShift, we need to define the following OpenShift configuration files within the defi-central-infra repository:

  • Deployment Configuration (deployment.yaml): Defines the deployment settings for the backend API, frontend, and SQL Server database for each environment.
  • Service Configuration (service.yaml): Defines how each component (backend API, frontend, SQL Server) will be exposed within OpenShift, including ports and load balancing.
  • Ingress Configuration (ingress.yaml): Configures routing rules and external access to the backend API and frontend services, including SSL/TLS termination settings for secure connections.

Sample OpenShift Configuration Files

1. Deployment Configuration (deployment.yaml)

This file defines the deployment configurations for both the backend and frontend components:

apiVersion: apps/v1
      kind: Deployment
      metadata:
      name: defi-central-backend
      namespace: defi-central-dev  # Change this for different environments
      spec:
      replicas: 3
      selector:
        matchLabels:
          app: defi-central-backend
      template:
        metadata:
          labels:
            app: defi-central-backend
        spec:
          containers:
          - name: backend-api
            image: myregistry/defi-central-backend:latest  # Replace with your image repository
            ports:
            - containerPort: 80
            envFrom:
            - secretRef:
                name: backend-secrets  # Reference to secret for environment variables
          imagePullSecrets:
            - name: my-registry-secret

      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
      name: defi-central-frontend
      namespace: defi-central-dev  # Change this for different environments
      spec:
      replicas: 2
      selector:
        matchLabels:
          app: defi-central-frontend
      template:
        metadata:
          labels:
            app: defi-central-frontend
        spec:
          containers:
          - name: frontend-app
            image: myregistry/defi-central-frontend:latest  # Replace with your image repository
            ports:
            - containerPort: 80
          imagePullSecrets:
            - name: my-registry-secret
            

2. Service Configuration (service.yaml)

Defines how the services are exposed within OpenShift.

apiVersion: v1
      kind: Service
      metadata:
      name: defi-central-backend-service
      namespace: defi-central-dev  # Change this for different environments
      spec:
      selector:
        app: defi-central-backend
      ports:
        - protocol: TCP
          port: 80
          targetPort: 80
      ---
      apiVersion: v1
      kind: Service
      metadata:
      name: defi-central-frontend-service
      namespace: defi-central-dev  # Change this for different environments
      spec:
      selector:
        app: defi-central-frontend
      ports:
        - protocol: TCP
          port: 80
          targetPort: 80
            

3. Ingress Configuration (ingress.yaml)

Configures external access to the application services.

apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
      name: defi-central-ingress
      namespace: defi-central-dev  # Change this for different environments
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /
        nginx.ingress.kubernetes.io/ssl-redirect: "true"
      spec:
      rules:
      - host: defi-central-dev.yourdomain.com  # Change host based on environment
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: defi-central-frontend-service
                port:
                  number: 80
      tls:
      - hosts:
        - defi-central-dev.yourdomain.com
        secretName: defi-central-tls  # Reference to the TLS secret
            

Deployment Process to OpenShift

Prepare the Deployment Files: Store all YAML configuration files (deployment.yaml, service.yaml, ingress.yaml) in the defi-central-infra/IaC/OpenShift/ directory of your infrastructure repository.

Authenticate to OpenShift: Use the OpenShift CLI (oc) to log in to your OpenShift cluster.

oc login --token=<your-token> --server=<openshift-server-url>

Deploy to OpenShift: Apply the deployment, service, and ingress configurations using oc commands:

oc apply -f defi-central-infra/IaC/OpenShift/deployment.yaml
      oc apply -f defi-central-infra/IaC/OpenShift/service.yaml
      oc apply -f defi-central-infra/IaC/OpenShift/ingress.yaml

Conclusion

By following this setup:

  • Environment Isolation: Each environment is isolated within its own OpenShift namespace.
  • Secure and Scalable: Use Azure Key Vault for secure secrets management and OpenShift for scalable on-premise hosting.
  • Automated Deployment: Use Azure DevOps Pipelines to automate deployments and ensure consistent infrastructure provisioning.

Pipeline Requirements for Defi-Central

Overview: To implement a robust CI/CD pipeline for "Defi-Central," we will define a set of Azure DevOps YAML pipelines for each component (backend, frontend, infrastructure) to automate the build, test, and deployment processes. The pipelines will be triggered by code changes in specific branches and pull requests, and will integrate various tools for code quality, security scanning, and package management.

Pipeline Triggers

  • Branch Commits: Pipelines will be triggered by commits to specific branches (e.g., main, develop).
  • Pull Requests: Pipelines will also be triggered for pull requests to ensure code quality and security checks before merging.

CI/CD Pipeline Structure

The pipeline structure consists of the following stages for both the backend and frontend:

  • Build Stage: Restore dependencies, compile code, and generate build artifacts. Publish build artifacts for further stages.
  • Test Stage: Run unit tests and integration tests. Perform static code analysis using SonarQube. Conduct security scanning with Checkmarx.
  • Deploy Stage: Deploy to the target environment (OpenShift). Apply EF Core migrations for the database or use a third-party tool (e.g., Flyway) for more complex scenarios.

Tools Used in the Pipeline

  • SonarQube: For static code analysis to ensure code quality.
  • Checkmarx: For security scanning to detect vulnerabilities in the codebase.
  • Nexus: For managing and hosting package dependencies.
  • EF Core: For handling database migrations.
  • Flyway: As an alternative tool for database versioning and management, providing advanced control over SQL scripts and rollbacks.

Backend CI/CD Pipeline Configuration (defi-central-backend/.azure-pipelines/backend-ci-cd.yml)

This pipeline automates the CI/CD process for the backend API.

trigger:
          branches:
            include:
              - '*'
        pr:
          branches:
            include:
              - '*'

        stages:
        - stage: Build
          displayName: 'Build Stage'
          jobs:
          - job: BuildBackend
            displayName: 'Build Backend API'
            pool:
              vmImage: 'windows-latest'
            steps:
            - task: UseDotNet@2
              inputs:
                packageType: 'sdk'
                version: '8.x'
            - script: |
                dotnet restore
                dotnet build --configuration Release
              displayName: 'Restore and Build Backend'
            - publish: '$(System.DefaultWorkingDirectory)/src/DefiCentral.Api/bin/Release'
              artifact: 'backend-api'

        - stage: Test
          displayName: 'Test Stage'
          dependsOn: Build
          jobs:
          - job: TestBackend
            displayName: 'Test Backend API'
            pool:
              vmImage: 'windows-latest'
            steps:
            - script: |
                dotnet test --configuration Release --collect "Code coverage"
              displayName: 'Run Unit and Integration Tests'
            - task: SonarQubePrepare@4
              inputs:
                SonarQube: ''
                scannerMode: 'MSBuild'
                configMode: 'manual'
                projectKey: 'defi-central-backend'
            - script: |
                dotnet build
              displayName: 'Run SonarQube Analysis'
            - task: SonarQubeAnalyze@4
            - task: CheckmarxScan@1
              inputs:
                checkmarxServerEndpoint: ''
                projectName: 'defi-central-backend'

        - stage: Deploy
          displayName: 'Deploy Stage'
          dependsOn: Test
          jobs:
          - job: DeployBackend
            displayName: 'Deploy Backend API to OpenShift'
            pool:
              vmImage: 'ubuntu-latest'
            steps:
            - script: |
                oc login --token=<token> --server=<openshift-url>
                oc apply -f defi-central-infra/IaC/OpenShift/deployment.yaml
                oc apply -f defi-central-infra/IaC/OpenShift/service.yaml
                oc apply -f defi-central-infra/IaC/OpenShift/ingress.yaml
              displayName: 'Deploy Backend to OpenShift'
                

Frontend CI/CD Pipeline Configuration (defi-central-frontend/.azure-pipelines/frontend-ci-cd.yml)

This pipeline handles the CI/CD process for the Angular frontend.

trigger:
          branches:
            include:
              - '*'
        pr:
          branches:
            include:
              - '*'

        stages:
        - stage: Build
          displayName: 'Build Stage'
          jobs:
          - job: BuildFrontend
            displayName: 'Build Frontend'
            pool:
              vmImage: 'ubuntu-latest'
            steps:
            - task: NodeTool@0
              inputs:
                versionSpec: '16.x'
              displayName: 'Install Node.js'
            - script: |
                npm install
                npm run build --prod
              displayName: 'Build Angular App'
            - publish: '$(Build.ArtifactStagingDirectory)'
              artifact: 'frontend-app'

        - stage: Test
          displayName: 'Test Stage'
          dependsOn: Build
          jobs:
          - job: TestFrontend
            displayName: 'Test Frontend'
            pool:
              vmImage: 'ubuntu-latest'
            steps:
            - script: npm test -- --watch=false --code-coverage
              displayName: 'Run Angular Unit Tests'
            - task: SonarQubePrepare@4
              inputs:
                SonarQube: '<SonarQube Service Connection>'
                scannerMode: 'CLI'
            - script: |
                npm run sonar-scanner
              displayName: 'Run SonarQube Analysis'
            - task: SonarQubeAnalyze@4
            - task: CheckmarxScan@1
              inputs:
                checkmarxServerEndpoint: '<Checkmarx Service Connection>'
                projectName: 'defi-central-frontend'

        - stage: Deploy
          displayName: 'Deploy Stage'
          dependsOn: Test
          jobs:
          - job: DeployFrontend
            displayName: 'Deploy Frontend to OpenShift'
            pool:
              vmImage: 'ubuntu-latest'
            steps:
            - script: |
                oc login --token=<token> --server=<openshift-url>
                oc apply -f defi-central-infra/IaC/OpenShift/deployment.yaml
                oc apply -f defi-central-infra/IaC/OpenShift/service.yaml
                oc apply -f defi-central-infra/IaC/OpenShift/ingress.yaml
              displayName: 'Deploy Frontend to OpenShift'
                

Quality Gates and Code Coverage

  • Unit Tests and Integration Tests: Both backend and frontend pipelines run unit and integration tests to ensure code quality.
  • SonarQube Integration: Static code analysis is performed, and quality gates are enforced (e.g., minimum 80% code coverage, no critical/blocker issues).
  • Checkmarx Integration: Security scanning is conducted to detect vulnerabilities according to OWASP standards.

Secrets and Credentials Management

Use Azure Key Vault to store sensitive information such as connection strings, API keys, and credentials. The pipeline will securely access secrets from Azure Key Vault using the AzureKeyVault@1 task.

- task: AzureKeyVault@1
          inputs:
            azureSubscription: '<Azure Service Connection>'
            KeyVaultName: '<KeyVaultName>'
            SecretsFilter: '*'
            RunAsPreJob: true
                

Conclusion

This pipeline structure ensures:

  • Continuous Integration: Automated build and test processes validate code quality at every change.
  • Continuous Deployment: Secure, automated deployments to OpenShift for all environments.
  • Compliance and Security: Integration with SonarQube, Checkmarx, and Azure Key Vault ensures code quality, security, and secret management.

Testing and Quality Gates for Defi-Central

Overview: To maintain a high level of code quality and security for "Defi-Central," we will implement comprehensive testing strategies and enforce quality gates in our CI/CD pipelines. This includes running automated tests, integrating with tools like SonarQube and Checkmarx, and defining thresholds for code quality, coverage, and security checks.

Testing Strategy

The testing strategy for "Defi-Central" involves multiple layers of automated tests:

  • Unit Tests: Verify individual components (functions, methods, or classes) in isolation. Implemented for both the backend (C# .NET 8) and frontend (Angular).
  • Integration Tests: Test the integration of multiple components (e.g., backend API endpoints with a test database). Ensure that components work together as expected. Focus on critical paths and interactions.
  • End-to-End (e2e) Tests: Validate the entire application workflow from start to finish. Conducted on the frontend using tools like Protractor or Cypress.
  • Security and Compliance Testing: Static code analysis using SonarQube to detect code quality issues. Security vulnerability scanning with Checkmarx. Compliance checks based on OWASP guidelines.

Test Tools and Frameworks

  • Backend (C# .NET 8): Use xUnit for unit testing. Use Moq or NSubstitute for mocking dependencies in unit tests. Use Microsoft.AspNetCore.TestHost for integration tests with an in-memory test server.
  • Frontend (Angular): Use Jasmine and Karma for unit testing of Angular components and services. Use Cypress or Protractor for end-to-end (e2e) tests.
  • Static Code Analysis: Use SonarQube to analyze code quality, identify code smells, and enforce quality gates.
  • Security Scanning: Use Checkmarx for static application security testing (SAST).

Quality Gates and Code Coverage Requirements

Quality Gates are a set of conditions that the code must meet before being considered for deployment. For "Defi-Central," the quality gates will enforce the following criteria:

  • Code Coverage: Minimum 80% code coverage for both backend and frontend. Ensure that all critical and high-severity lines of code are covered.
  • Code Quality: No blocker or critical issues detected by SonarQube. Zero security vulnerabilities detected by Checkmarx.
  • Compliance: Compliance with OWASP standards for security.

Implementing Testing and Quality Gates in Azure DevOps Pipelines

1. Backend Pipeline Testing Configuration

In the backend-ci-cd.yml pipeline, we will add steps to run tests, analyze code quality, and enforce quality gates.

stages:
        - stage: Build
          displayName: 'Build Stage'
          jobs:
          - job: BuildBackend
            displayName: 'Build Backend API'
            pool:
              vmImage: 'windows-latest'
            steps:
            - task: UseDotNet@2
              inputs:
                packageType: 'sdk'
                version: '8.x'
            - script: |
                dotnet restore
                dotnet build --configuration Release
              displayName: 'Restore and Build Backend'
            - publish: '$(System.DefaultWorkingDirectory)/src/DefiCentral.Api/bin/Release'
              artifact: 'backend-api'

        - stage: Test
          displayName: 'Test Stage'
          dependsOn: Build
          jobs:
          - job: TestBackend
            displayName: 'Test Backend API'
            pool:
              vmImage: 'windows-latest'
            steps:
            - script: |
                dotnet test --configuration Release --collect "Code coverage" --logger trx --results-directory $(Build.SourcesDirectory)/TestResults
              displayName: 'Run Unit and Integration Tests'
            - task: PublishTestResults@2
              inputs:
                testResultsFormat: 'VSTest'
                testResultsFiles: '**/*.trx'
                mergeTestResults: true
                failTaskOnFailedTests: true
              displayName: 'Publish Test Results'
            - task: SonarQubePrepare@4
              inputs:
                SonarQube: '<SonarQube Service Connection>'
                scannerMode: 'MSBuild'
                configMode: 'manual'
                projectKey: 'defi-central-backend'
            - script: |
                dotnet build
              displayName: 'Run SonarQube Analysis'
            - task: SonarQubeAnalyze@4
            - task: SonarQubePublish@4
              inputs:
                pollingTimeoutSec: '300'
              displayName: 'Publish SonarQube Quality Gate Results'
            - task: CheckmarxScan@1
              inputs:
                checkmarxServerEndpoint: '<Checkmarx Service Connection>'
                projectName: 'defi-central-backend'
                threshold: 'High'  # Set the level of issue threshold
                

2. Frontend Pipeline Testing Configuration

In the frontend-ci-cd.yml pipeline, we will add steps to run unit and e2e tests, analyze code quality, and enforce quality gates.

stages:
        - stage: Build
          displayName: 'Build Stage'
          jobs:
          - job: BuildFrontend
            displayName: 'Build Frontend'
            pool:
              vmImage: 'ubuntu-latest'
            steps:
            - task: NodeTool@0
              inputs:
                versionSpec: '16.x'
              displayName: 'Install Node.js'
            - script: |
                npm install
                npm run build --prod
              displayName: 'Build Angular App'
            - publish: '$(Build.ArtifactStagingDirectory)'
              artifact: 'frontend-app'

        - stage: Test
          displayName: 'Test Stage'
          dependsOn: Build
          jobs:
          - job: TestFrontend
            displayName: 'Test Frontend'
            pool:
              vmImage: 'ubuntu-latest'
            steps:
            - script: npm test -- --watch=false --code-coverage --browsers=ChromeHeadless
              displayName: 'Run Angular Unit Tests'
            - task: PublishTestResults@2
              inputs:
                testResultsFormat: 'JUnit'
                testResultsFiles: '**/TEST-*.xml'
                failTaskOnFailedTests: true
              displayName: 'Publish Unit Test Results'
            - task: SonarQubePrepare@4
              inputs:
                SonarQube: '<SonarQube Service Connection>'
                scannerMode: 'CLI'
            - script: |
                npm run sonar-scanner
              displayName: 'Run SonarQube Analysis'
            - task: SonarQubeAnalyze@4
            - task: SonarQubePublish@4
              inputs:
                pollingTimeoutSec: '300'
              displayName: 'Publish SonarQube Quality Gate Results'
            - task: CheckmarxScan@1
              inputs:
                checkmarxServerEndpoint: '<Checkmarx Service Connection>'
                projectName: 'defi-central-frontend'
                threshold: 'High'  # Set the level of issue threshold
                

Conclusion

By integrating these testing and quality gate steps in Azure DevOps pipelines:

  • Ensures High Code Quality: Regular automated testing and static code analysis maintain a high standard of code quality.
  • Secures the Application: Security scans detect vulnerabilities early, adhering to compliance requirements.
  • Provides Continuous Feedback: Developers receive continuous feedback on the code's health, enabling rapid iterations and improvements.

Additional Tools or Integrations for Defi-Central

Overview: To ensure "Defi-Central" is thoroughly tested, secure, and observable in all environments, we'll integrate the following tools:

  • Xray: For managing manual testing within Azure DevOps.
  • UiPath Test Suite: For automated testing, including robotic process automation (RPA) and other end-to-end test cases.
  • Monitoring Tools (Grafana and ELK Stack): For application monitoring, performance analysis, and centralized logging.

These tools will be integrated with Azure DevOps to create a seamless workflow that encompasses manual and automated testing, monitoring, and logging.

1. Integrating Xray for Manual Testing

Xray is a popular test management tool that integrates with Azure DevOps to manage and execute manual tests, track test results, and report defects. It enhances test management capabilities by providing a robust interface for managing test cases, plans, and executions.

Steps to Integrate Xray with Azure DevOps:

  • Set Up Xray in Azure DevOps:
    • Install the Xray Test Management for Azure DevOps extension from the Azure DevOps marketplace.
    • Navigate to your Azure DevOps project, and go to Project Settings > Extensions > Xray Test Management.
    • Configure the Xray extension by connecting it to your Xray Cloud or Server instance.
  • Define Test Cases and Plans: Create Test Cases directly in Azure DevOps under the Test Plans section. Use the Xray-specific fields to define detailed test steps, preconditions, and expected results.
  • Link Tests to Pipeline: Use the Xray tasks in Azure DevOps pipelines to link test cases and results. Add a pipeline task to execute manual test cases using Xray:
    - task: XrayExecuteTests@1
              inputs:
                testPlanKey: '<Test Plan Key>'
                credentials: '<Xray Credentials>'
  • Publish Test Results: After executing tests, use Xray APIs to publish test results back to Azure DevOps, ensuring visibility of manual test outcomes.
    curl -u <username>:<password> -X POST -F "info=@test_info.json" https://xray.cloud.xpand-it.com/api/v2/import/execution

2. Integrating UiPath Test Suite for Automated Testing

UiPath Test Suite offers comprehensive capabilities for automated testing, including robotic process automation (RPA) and end-to-end application testing. It allows you to automate repetitive tasks, simulate user interactions, and validate complex business workflows.

Steps to Integrate UiPath Test Suite with Azure DevOps:

  • Set Up UiPath in Azure DevOps:
    • Install the UiPath Integration for Azure DevOps extension from the Azure DevOps marketplace.
    • Create a Service Connection in Azure DevOps to connect to your UiPath Orchestrator. Go to Project Settings > Service connections > New service connection > UiPath.
    • Provide the necessary details like the Orchestrator URL, Tenant Name, Username, and API Key.
  • Configure UiPath Pipeline Tasks: Define pipeline tasks to trigger UiPath test cases and retrieve results. Add the following YAML snippet to your pipeline to execute UiPath automated tests:
    - task: UiPathRunJob@2
              inputs:
                processName: 'DefiCentral_UiPath_Test'
                orchestratorFolderPath: '/DefiCentral'
                orchestratorTenant: 'default'
                orchestratorUrl: 'https://your-orchestrator-url'
                username: 'your-username'
                password: 'your-password'
                failTaskIfTestsFail: true
  • Publish UiPath Test Results: Use the UiPath Test Manager to collect test results and publish them to Azure DevOps.
    uipath-cli test run --test-set "DefiCentral Tests" --results-format "junit"

3. Integrating Monitoring and Logging Tools

To ensure "Defi-Central" is observable in all environments, we will integrate Grafana and ELK Stack for monitoring and centralized logging.

Grafana for Monitoring

Grafana is an open-source monitoring tool that provides a powerful interface for visualizing metrics, creating dashboards, and alerting. It can be integrated with Azure DevOps to monitor application health and performance metrics.

Steps to Integrate Grafana:

  • Set Up Grafana on OpenShift: Deploy Grafana on your OpenShift cluster using an Operator or Helm chart. Configure Grafana to connect to your data sources (e.g., Prometheus, Elasticsearch).
  • Configure Data Sources and Dashboards: Add Prometheus or Elasticsearch as a data source in Grafana to collect metrics and logs from your application. Create dashboards to visualize application performance, error rates, and key metrics.
  • Integrate with Azure DevOps Pipelines: Use the Grafana API to automate the creation of dashboards and alerts during pipeline execution.
    curl -X POST -H "Authorization: Bearer <API_KEY>" -H "Content-Type: application/json" \
            -d @dashboard.json https://<grafana-server>/api/dashboards/db

ELK Stack for Centralized Logging

ELK Stack (Elasticsearch, Logstash, Kibana) is a widely used solution for centralized logging and log analysis. It allows you to aggregate logs from different sources and provides a powerful search and visualization interface.

Steps to Integrate ELK Stack:

  • Deploy ELK Stack on OpenShift: Deploy Elasticsearch, Logstash, and Kibana on your OpenShift cluster using Helm or Operators. Configure Filebeat or Fluentd to collect logs from the application and send them to Elasticsearch.
  • Configure Logging and Index Patterns: Define Index Patterns in Kibana to categorize logs for different components (e.g., backend, frontend). Set up Logstash pipelines to filter and transform logs before indexing in Elasticsearch.
  • Integrate with Azure DevOps Pipelines: Add steps to your pipeline to validate logs or check for specific patterns as part of your deployment process. Use the Elasticsearch API to query logs and generate reports:
    curl -X GET "https://<elasticsearch-server>:9200/_search?q=error&pretty"

Conclusion

By integrating these additional tools into your CI/CD pipeline for "Defi-Central":

  • Xray and UiPath: Provide comprehensive testing coverage for both manual and automated scenarios.
  • Grafana and ELK Stack: Enhance observability, monitoring, and logging capabilities, ensuring robust performance and reliability in production environments.

Security and Compliance for Defi-Central

Overview: To secure "Defi-Central" and ensure compliance with industry standards, we'll implement a security strategy that includes:

  • Secrets and Credentials Management: Using Azure Key Vault for secure storage of sensitive information.
  • Security Scanning and Vulnerability Assessment: Integrating tools like Checkmarx and SonarQube to identify and mitigate security vulnerabilities.
  • Compliance with OWASP Standards: Enforcing security checks and compliance requirements based on the OWASP Top 10 guidelines.

1. Secrets and Credentials Management

To securely store and manage secrets, credentials, and other sensitive data, we will use Azure Key Vault. This service provides centralized storage for secrets, certificates, and encryption keys with access control and auditing capabilities.

Steps to Integrate Azure Key Vault with Azure DevOps:

  • Create an Azure Key Vault:
    • Go to the Azure portal and create a new Azure Key Vault resource.
    • Define access policies to grant necessary permissions (e.g., Get, List, Delete) to specific Azure Active Directory users or applications.
  • Store Secrets in Azure Key Vault: Add secrets, such as database connection strings, API keys, and certificates, to Azure Key Vault.
    az keyvault secret set --vault-name "DefiCentralVault" --name "DbConnectionString" --value "<connection-string>"
            az keyvault secret set --vault-name "DefiCentralVault" --name "ApiKey" --value "<api-key>"
  • Create a Service Connection in Azure DevOps: In Azure DevOps, go to Project Settings > Service Connections > New Service Connection > Azure Resource Manager. Choose Service Principal (automatic) and select the Azure subscription and Key Vault you created.
  • Use Azure Key Vault in Your Pipelines: Use the AzureKeyVault@1 task to retrieve secrets and use them securely in your pipelines.
    - task: AzureKeyVault@1
              inputs:
                azureSubscription: '<Azure Service Connection>'
                KeyVaultName: 'DefiCentralVault'
                SecretsFilter: '*'
                RunAsPreJob: true

2. Security Scanning and Vulnerability Assessment

To ensure that "Defi-Central" is secure from vulnerabilities, we'll use a combination of Checkmarx for static application security testing (SAST) and SonarQube for static code analysis.

Checkmarx Integration for Security Scanning

Checkmarx is a leading SAST tool that helps detect security vulnerabilities in the source code by scanning it against known vulnerability patterns.

Steps to Integrate Checkmarx with Azure DevOps:

  • Install Checkmarx Extension: Install the Checkmarx extension from the Azure DevOps marketplace.
  • Set Up a Service Connection for Checkmarx: In Azure DevOps, go to Project Settings > Service Connections > New Service Connection > Checkmarx. Provide the necessary details, such as the Checkmarx server URL, username, and API key.
  • Add Checkmarx Scan Task to the Pipeline: Include the CheckmarxScan@1 task in your Azure DevOps pipeline to perform security scans.
    - task: CheckmarxScan@1
              inputs:
                checkmarxServerEndpoint: '<Checkmarx Service Connection>'
                projectName: 'defi-central-backend'
                threshold: 'High'  # Enforce thresholds for scan results

SonarQube Integration for Static Code Analysis

SonarQube is a static code analysis tool that detects code quality issues, bugs, and security vulnerabilities.

Steps to Integrate SonarQube with Azure DevOps:

  • Set Up SonarQube Server: Deploy a SonarQube server on-premises or use a managed SonarQube service. Create a project in SonarQube for "Defi-Central."
  • Create a SonarQube Service Connection: In Azure DevOps, navigate to Project Settings > Service Connections > New Service Connection > SonarQube. Provide the SonarQube server URL, token, and other necessary details.
  • Add SonarQube Tasks to the Pipeline: Include SonarQubePrepare@4, SonarQubeAnalyze@4, and SonarQubePublish@4 tasks in the pipeline to analyze code and enforce quality gates.
    - task: SonarQubePrepare@4
              inputs:
                SonarQube: '<SonarQube Service Connection>'
                scannerMode: 'MSBuild'
                configMode: 'manual'
                projectKey: 'defi-central-backend'
            - script: |
                dotnet build
              displayName: 'Run SonarQube Analysis'
            - task: SonarQubeAnalyze@4
            - task: SonarQubePublish@4
              inputs:
                pollingTimeoutSec: '300'
              displayName: 'Publish SonarQube Quality Gate Results'

3. Compliance with OWASP Standards

OWASP (Open Web Application Security Project) provides guidelines for application security, focusing on the most common vulnerabilities found in web applications.

Steps to Ensure Compliance with OWASP Standards:

  • Configure OWASP Checks in Checkmarx: Enable OWASP Top 10 checks in the Checkmarx security scan configuration. Ensure that all security scans are conducted according to OWASP guidelines.
  • Include OWASP Dependency Check in Pipelines: Use OWASP Dependency-Check to scan for vulnerable third-party dependencies.
    - script: |
                dependency-check.sh --project "Defi-Central" --scan . --format "ALL"
              displayName: 'Run OWASP Dependency Check'
  • Define Compliance Policies in Azure DevOps: Set up branch policies in Azure Repos to require passing security checks and quality gates before merging code.
  • Automate OWASP ZAP Scans: Use OWASP ZAP (Zed Attack Proxy) for dynamic application security testing (DAST) to identify vulnerabilities in running applications.
    - script: |
                zap-cli quick-scan --self-contained --start-options "-config api.disablekey=true" http://your-app-url
              displayName: 'Run OWASP ZAP DAST Scan'

Conclusion

By integrating these security and compliance practices into your CI/CD pipeline for "Defi-Central":

  • Azure Key Vault: Securely manages secrets and credentials.
  • Checkmarx and SonarQube: Automate security and code quality checks, ensuring compliance with OWASP standards.
  • OWASP ZAP and Dependency-Check: Provide additional layers of security by identifying runtime vulnerabilities and issues with third-party dependencies.

Developer Experience for Defi-Central

Overview: To enhance the developer experience for "Defi-Central," we will focus on the following areas:

  • Preferred Development Environment: Setting up and configuring Visual Studio 2022 for backend development and Visual Studio Code for frontend development.
  • Local Development Setup: Providing scripts and tools for easy local environment setup, including dependencies, database migrations, and local servers.
  • Guidelines and Best Practices: Establishing coding standards, commit guidelines, and best practices to ensure code quality and maintainability.

1. Preferred Development Environment

Backend Development with Visual Studio 2022

Visual Studio 2022 is a powerful integrated development environment (IDE) that offers advanced features for .NET development, including support for C# .NET 8, built-in testing tools, code refactoring, debugging, and Git integration.

Steps to Set Up Visual Studio 2022:

  • Install Visual Studio 2022: Download and install Visual Studio 2022 from the Visual Studio official website. Select the .NET Desktop Development and ASP.NET and Web Development workloads during installation to ensure all required components are installed.
  • Clone the Backend Repository: Use Git to clone the defi-central-backend repository.
    git clone https://your-repo-url/defi-central-backend.git
  • Open the Solution in Visual Studio: Open the DefiCentral.sln solution file in Visual Studio 2022.
  • Install Required Extensions: Install recommended extensions for .NET development:
    • ReSharper for advanced code analysis and refactoring.
    • SonarLint for in-IDE static code analysis to detect issues early.
    • Azure DevOps extension for integrated pipeline management and work item tracking.
  • Configure Debugging and Run Settings: Configure Visual Studio to use the built-in IIS Express or Kestrel web server for local debugging. Set breakpoints and run the application in Debug mode to step through code and diagnose issues.
  • Use Visual Studio for Testing: Leverage Test Explorer to run and debug unit tests. Ensure code coverage by running tests and analyzing results within Visual Studio.

Frontend Development with Visual Studio Code

Visual Studio Code (VS Code) is a lightweight, cross-platform code editor ideal for frontend development with Angular. It offers a wide range of extensions, built-in Git support, and an integrated terminal.

Steps to Set Up Visual Studio Code:

  • Install Visual Studio Code: Download and install Visual Studio Code from the Visual Studio Code official website.
  • Clone the Frontend Repository: Use Git to clone the defi-central-frontend repository.
    git clone https://your-repo-url/defi-central-frontend.git
  • Open the Project in Visual Studio Code: Open the defi-central-frontend folder in Visual Studio Code.
  • Install Recommended Extensions: Install the following recommended extensions for Angular development:
    • Angular Language Service: Provides code navigation, refactoring, and auto-completion for Angular projects.
    • ESLint: Enforces consistent coding standards and identifies potential errors.
    • Debugger for Chrome: Allows debugging of Angular applications directly from VS Code.
    • Prettier: Automatically formats code according to a consistent style guide.
  • Set Up Integrated Terminal: Use the integrated terminal in VS Code to run common commands, such as:
    npm install
            npm start  # Start the Angular development server
            npm test   # Run unit tests
  • Use Live Server and Debugging Tools: Use the Live Server extension for real-time development and live reloading. Configure debugging settings to connect to the local Angular development server.

2. Local Development Setup

To streamline the local development process, provide scripts and tools that automate environment setup and common tasks, reducing the time required to get started.

Backend Setup Scripts

Create a script (setup-backend.ps1 for Windows or setup-backend.sh for Linux/macOS) to set up the backend environment, including installing dependencies, initializing the database, and running migrations.

Sample setup-backend.ps1 Script:

# Check and install required .NET SDK
        $dotnetVersion = "8.0"
        if (!(dotnet --list-sdks | Select-String $dotnetVersion)) {
            Write-Host "Installing .NET SDK $dotnetVersion..."
            Install-Package -Name dotnet-sdk -Source chocolatey
        }

        # Restore NuGet packages
        Write-Host "Restoring NuGet packages..."
        dotnet restore

        # Apply EF Core migrations to the local database
        Write-Host "Applying EF Core migrations..."
        dotnet ef database update

        Write-Host "Backend environment setup complete!"

Frontend Setup Scripts

Create a script (setup-frontend.sh) to automate the frontend environment setup, such as installing Node.js dependencies, running tests, and starting the development server.

Sample setup-frontend.sh Script:

#!/bin/bash

        # Install Node.js dependencies
        echo "Installing Node.js dependencies..."
        npm install

        # Run initial unit tests to ensure the environment is set up correctly
        echo "Running unit tests..."
        npm test

        # Start the development server
        echo "Starting the Angular development server..."
        npm start

Database Initialization Scripts

Provide scripts to initialize and populate the local development database with test data. Store these scripts in the scripts/ folder of the backend repository.

Sample init-db.ps1 Script:

# Initialize the SQL Server Database for Local Development

        # Connection details
        $server = "localhost"
        $database = "DefiCentralDB"
        $connectionString = "Server=$server;Database=$database;Integrated Security=True;"

        # Create the database
        Write-Host "Creating local database..."
        sqlcmd -S $server -Q "CREATE DATABASE [$database]"

        # Run EF Core migrations
        Write-Host "Applying EF Core migrations..."
        dotnet ef database update

        Write-Host "Database initialized successfully!"

3. Guidelines and Best Practices

To maintain code quality and consistency across the team, establish clear guidelines and best practices:

Coding Standards

Follow consistent coding standards for C# and TypeScript:

  • Use the Microsoft .NET Coding Guidelines for C#.
  • Use the Angular Style Guide for TypeScript and Angular projects.
  • Enforce coding standards using tools like ESLint (for TypeScript) and SonarLint (for C#) in the IDE.

Commit Guidelines

Use a consistent commit message format:

  • feat: A new feature
  • fix: A bug fix
  • docs: Documentation changes
  • style: Code style changes (formatting, etc.)
  • refactor: Code refactoring without changing functionality
  • test: Adding or updating tests
  • chore: Maintenance tasks, such as dependency updates

Example Commit Message:

feat(api): Add user authentication endpoint

        - Implement JWT-based authentication for user login
        - Add unit tests for authentication service

Code Review and Pull Request Guidelines

Set up branch policies in Azure DevOps to require pull requests for merging code into main branches. Require at least one reviewer approval for every pull request. Run automated tests and checks (SonarQube, Checkmarx) on pull request builds to ensure code quality.

Documentation and Onboarding

Provide comprehensive README.md files in each repository to describe the project structure, setup instructions, and common tasks. Create a developer guide with onboarding steps, common workflows, and troubleshooting tips.

Conclusion

By setting up a well-defined development environment and guidelines:

  • Boosts Developer Productivity: Ensures developers can start contributing quickly and effectively.
  • Maintains Code Quality: Enforces standards and best practices across the team.
  • Facilitates Collaboration: Provides a unified workflow for development, testing, and code reviews.

Conclusion

This comprehensive tutorial for "Defi-Central" provides a step-by-step guide to setting up a robust and scalable Azure DevOps CI/CD pipeline and infrastructure for a full-stack application with a .NET 8 backend, an Angular frontend, and an SQL Server database. By following this tutorial, both experienced and new developers can ensure a smooth and efficient process for building, testing, and deploying the application.

Key Takeaways:

Project Setup and Structure:

  • Organized into multiple repositories (backend, frontend, and infrastructure), ensuring modular development and facilitating easier management and scalability.
  • Clear separation of concerns allows for parallel development and independent version control, reducing conflicts and improving maintainability.

Infrastructure and Environments:

  • Defined environments (DEV, Integration, UAT, PROD) and deployment targets (OpenShift) ensure a consistent and reliable deployment process.
  • OpenShift configurations (deployments, services, and ingress rules) enable secure, scalable, and automated deployments in an on-premises environment.

Pipeline Requirements:

  • Well-structured Azure DevOps pipelines automate the build, test, and deployment stages, integrating tools like SonarQube for code quality, Checkmarx for security, and Nexus for package management.
  • Pipeline triggers ensure continuous integration and delivery, reducing manual errors and speeding up the deployment cycle.

Testing and Quality Gates:

  • Comprehensive testing strategies, including unit tests, integration tests, end-to-end tests, and security scans, ensure high code quality and application security.
  • Integration of quality gates with SonarQube and Checkmarx enforces coding standards and security compliance, providing continuous feedback and maintaining a high standard of delivery.

Additional Tools and Integrations:

  • Integrations with Xray for manual testing, UiPath Test Suite for automated testing, and Grafana and ELK Stack for monitoring and logging, provide a full spectrum of testing and observability capabilities.
  • This enhances both application quality and developer productivity, enabling quick identification and resolution of issues.

Security and Compliance:

  • Secure secrets management with Azure Key Vault, and automated vulnerability assessments with Checkmarx and SonarQube, ensure compliance with OWASP standards.
  • Regular security scanning and the use of OWASP ZAP and Dependency-Check mitigate potential risks and maintain a proactive security posture.

Developer Experience:

  • A well-defined development environment setup, supported by Visual Studio 2022 and Visual Studio Code, boosts developer productivity and streamlines the onboarding process.
  • Clear guidelines, best practices, and automation scripts simplify the development process and ensure consistent code quality across the team.

Final Thoughts:

By implementing the strategies, tools, and practices outlined in this tutorial, "Defi-Central" will benefit from a well-organized and automated CI/CD pipeline that promotes rapid and reliable delivery of high-quality code. The comprehensive approach to security, testing, monitoring, and developer experience ensures that the application is not only functional and scalable but also secure and maintainable.

This setup empowers your team to focus on delivering value to users while the automated processes handle the complexities of integration, testing, deployment, and compliance. As you continue to enhance "Defi-Central," this solid foundation will allow you to scale efficiently, maintain high standards, and adapt quickly to changing requirements.

Next Steps:

  • Monitor and Optimize Pipelines: Regularly review and optimize your CI/CD pipelines to improve performance and reduce build times.
  • Continuous Improvement: Encourage feedback from developers and stakeholders to identify areas for further automation and enhancement.
  • Stay Up-to-Date: Keep up with the latest updates and best practices for Azure DevOps, .NET, Angular, and security tools to ensure your pipelines remain current and secure.

By leveraging the tools and practices outlined in this guide, "Defi-Central" will be well-equipped to meet the demands of a dynamic, fast-paced development environment, delivering a high-quality product with confidence and agility.

Facebook Facebook Twitter Twitter LinkedIn LinkedIn Email Email Reddit Reddit Pinterest Pinterest WhatsApp WhatsApp Telegram Telegram VK VK



Consent Preferences


Capsule 1: Object-Oriented Design
Capsule 2: Design Patterns
Capsule 3: Software Architecture
Capsule 4: Service-Oriented Architecture (SOA)
Capsule 5: Advanced Topics in Software Architecture
Capsule 6: Clean Code and Testing Strategies
Capsule 7: Modern Development Practices
Capsule 8: Capstone Project and Assessment
Tooling: Best of the breed tooling for training
Tutorial: Setting up Azure DevOps Infrastructure and Pipelines for a Full-Stack .NET 8 Application
Accelerating Software Delivery with DevOps and CI/CD
Further Readings
Welcome to DevHub
Tools
Tutorials
DeFi Central 3
DeFi Central 2
DeFi Central 1
Google search ...