{"id":113,"date":"2024-01-28T19:02:01","date_gmt":"2024-01-28T19:02:01","guid":{"rendered":"https:\/\/davagordon.co.uk\/blog\/?p=113"},"modified":"2024-05-12T02:31:18","modified_gmt":"2024-05-12T01:31:18","slug":"setting-up-azure-pipelines-for-net-projects-with-quality-tests-and-sonarcloud","status":"publish","type":"post","link":"https:\/\/davagordon.co.uk\/blog\/setting-up-azure-pipelines-for-net-projects-with-quality-tests-and-sonarcloud\/","title":{"rendered":"Setting Up Azure Pipelines for .NET Projects with Quality Tests and SonarCloud"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">In the realm of .NET development, establishing a robust CI\/CD pipeline is vital for ensuring code quality and delivering reliable software. Azure Pipelines, part of the Azure DevOps suite, provides a seamless solution for automating build and deployment processes. In this tutorial, we&#8217;ll guide you through the process of setting up Azure Pipelines for a .NET project, complete with quality tests and SonarCloud integration.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites:<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Azure DevOps Account:<\/strong><br><ul><li>Sign up for an Azure DevOps account at <a href=\"https:\/\/dev.azure.com\/.\" target=\"_blank\" rel=\"noopener\" title=\"Azure\">https:\/\/dev.azure.com\/.<\/a><\/li><\/ul><\/li>\n\n\n\n<li><strong>.NET Core SDK:<\/strong><ul><li>Install the latest version of the .NET Core SDK from https:\/\/dotnet.microsoft.com\/download.<\/li><\/ul><\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Create a New Project and Repository<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Azure DevOps Project:<\/strong><ul><li>Log in to your Azure DevOps account and create a new project.<\/li><\/ul><\/li>\n\n\n\n<li><strong>Source Code Repository:<\/strong><ul><li>Connect your preferred source code repository (e.g., GitHub, Bitbucket, Azure Repos) to your project.<\/li><\/ul><\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Configure the <code>azure-pipelines.yml<\/code> File<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Create an <code>azure-pipelines.yml<\/code> file at the root of your .NET project. Copy and customize the following configuration:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\ntrigger:\n- main\n\npool:\n  vmImage: &#039;windows-latest&#039;\n\njobs:\n- job: Build\n  displayName: &#039;Build and Test&#039;\n  steps:\n  - task: UseDotNet@2\n    inputs:\n      version: &#039;3.x&#039;\n      installationPath: $(Agent.ToolsDirectory)\/dotnet\n\n  - script: dotnet restore\n    displayName: &#039;Restore Dependencies&#039;\n\n  - script: dotnet build --configuration Release\n    displayName: &#039;Build Solution&#039;\n\n  - script: dotnet test --configuration Release --collect:&quot;XPlat Code Coverage&quot;\n    displayName: &#039;Run Unit Tests&#039;\n    env:\n      DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true\n      DOTNET_CLI_TELEMETRY_OPTOUT: true\n\n  - task: PublishCodeCoverageResults@1\n    inputs:\n      codeCoverageTool: &#039;Cobertura&#039;\n      summaryFileLocation: &#039;$(Agent.TempDirectory)\/**\/coverage.cobertura.xml&#039;\n      failIfCoverageEmpty: true\n    displayName: &#039;Publish Code Coverage&#039;\n\n- job: QualityCheck\n  displayName: &#039;Run Quality Checks&#039;\n  dependsOn: Build\n  steps:\n  - task: SonarCloudPrepare@1\n    inputs:\n      SonarCloud: &#039;YourSonarCloudServiceConnection&#039;\n      organization: &#039;YourSonarCloudOrganization&#039;\n      projectKey: &#039;YourProjectKey&#039;\n      projectName: &#039;YourProjectName&#039;\n      scannerMode: &#039;MSBuild&#039;\n\n  - script: |\n      # Additional quality checks or static code analysis tools can be added here\n    displayName: &#039;Additional Quality Checks&#039;\n\n  - task: SonarCloudAnalyze@1\n\n  - task: SonarCloudPublish@1\n    inputs:\n      pollingTimeoutSec: &#039;300&#039;\n\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"><span style=\"color: rgb(55, 65, 81); font-family: S\u00f6hne, ui-sans-serif, system-ui, -apple-system, &quot;Segoe UI&quot;, Roboto, Ubuntu, Cantarell, &quot;Noto Sans&quot;, sans-serif, &quot;Helvetica Neue&quot;, Arial, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;, &quot;Noto Color Emoji&quot;; font-size: 16px;\">Replace the placeholders like <\/span><code style=\"border: 0px solid rgb(217, 217, 227); box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-pan-x: ; --tw-pan-y: ; --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; --tw-gradient-from-position: ; --tw-gradient-via-position: ; --tw-gradient-to-position: ; --tw-ordinal: ; --tw-slashed-zero: ; --tw-numeric-figure: ; --tw-numeric-spacing: ; --tw-numeric-fraction: ; --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-shadow: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-shadow-colored: 0 0 transparent; --tw-blur: ; --tw-brightness: ; --tw-contrast: ; --tw-grayscale: ; --tw-hue-rotate: ; --tw-invert: ; --tw-saturate: ; --tw-sepia: ; --tw-drop-shadow: ; --tw-backdrop-blur: ; --tw-backdrop-brightness: ; --tw-backdrop-contrast: ; --tw-backdrop-grayscale: ; --tw-backdrop-hue-rotate: ; --tw-backdrop-invert: ; --tw-backdrop-opacity: ; --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; font-size: 0.875em; color: var(--tw-prose-code); font-weight: 600; font-family: &quot;S\u00f6hne Mono&quot;, Monaco, &quot;Andale Mono&quot;, &quot;Ubuntu Mono&quot;, monospace !important;\">'<\/code><code>YourSonarCloudServiceConnection<\/code><code style=\"border: 0px solid rgb(217, 217, 227); box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-pan-x: ; --tw-pan-y: ; --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; --tw-gradient-from-position: ; --tw-gradient-via-position: ; --tw-gradient-to-position: ; --tw-ordinal: ; --tw-slashed-zero: ; --tw-numeric-figure: ; --tw-numeric-spacing: ; --tw-numeric-fraction: ; --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-shadow: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-shadow-colored: 0 0 transparent; --tw-blur: ; --tw-brightness: ; --tw-contrast: ; --tw-grayscale: ; --tw-hue-rotate: ; --tw-invert: ; --tw-saturate: ; --tw-sepia: ; --tw-drop-shadow: ; --tw-backdrop-blur: ; --tw-backdrop-brightness: ; --tw-backdrop-contrast: ; --tw-backdrop-grayscale: ; --tw-backdrop-hue-rotate: ; --tw-backdrop-invert: ; --tw-backdrop-opacity: ; --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; font-size: 0.875em; color: var(--tw-prose-code); font-weight: 600; font-family: &quot;S\u00f6hne Mono&quot;, Monaco, &quot;Andale Mono&quot;, &quot;Ubuntu Mono&quot;, monospace !important;\">'<\/code><span style=\"color: rgb(55, 65, 81); font-family: S\u00f6hne, ui-sans-serif, system-ui, -apple-system, &quot;Segoe UI&quot;, Roboto, Ubuntu, Cantarell, &quot;Noto Sans&quot;, sans-serif, &quot;Helvetica Neue&quot;, Arial, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;, &quot;Noto Color Emoji&quot;; font-size: 16px;\">, <\/span><code style=\"border: 0px solid rgb(217, 217, 227); box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-pan-x: ; --tw-pan-y: ; --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; --tw-gradient-from-position: ; --tw-gradient-via-position: ; --tw-gradient-to-position: ; --tw-ordinal: ; --tw-slashed-zero: ; --tw-numeric-figure: ; --tw-numeric-spacing: ; --tw-numeric-fraction: ; --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-shadow: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-shadow-colored: 0 0 transparent; --tw-blur: ; --tw-brightness: ; --tw-contrast: ; --tw-grayscale: ; --tw-hue-rotate: ; --tw-invert: ; --tw-saturate: ; --tw-sepia: ; --tw-drop-shadow: ; --tw-backdrop-blur: ; --tw-backdrop-brightness: ; --tw-backdrop-contrast: ; --tw-backdrop-grayscale: ; --tw-backdrop-hue-rotate: ; --tw-backdrop-invert: ; --tw-backdrop-opacity: ; --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; font-size: 0.875em; color: var(--tw-prose-code); font-weight: 600; font-family: &quot;S\u00f6hne Mono&quot;, Monaco, &quot;Andale Mono&quot;, &quot;Ubuntu Mono&quot;, monospace !important;\">'<\/code><code>YourSonarCloudOrganization<\/code><code style=\"border: 0px solid rgb(217, 217, 227); box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-pan-x: ; --tw-pan-y: ; --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; --tw-gradient-from-position: ; --tw-gradient-via-position: ; --tw-gradient-to-position: ; --tw-ordinal: ; --tw-slashed-zero: ; --tw-numeric-figure: ; --tw-numeric-spacing: ; --tw-numeric-fraction: ; --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-shadow: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-shadow-colored: 0 0 transparent; --tw-blur: ; --tw-brightness: ; --tw-contrast: ; --tw-grayscale: ; --tw-hue-rotate: ; --tw-invert: ; --tw-saturate: ; --tw-sepia: ; --tw-drop-shadow: ; --tw-backdrop-blur: ; --tw-backdrop-brightness: ; --tw-backdrop-contrast: ; --tw-backdrop-grayscale: ; --tw-backdrop-hue-rotate: ; --tw-backdrop-invert: ; --tw-backdrop-opacity: ; --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; font-size: 0.875em; color: var(--tw-prose-code); font-weight: 600; font-family: &quot;S\u00f6hne Mono&quot;, Monaco, &quot;Andale Mono&quot;, &quot;Ubuntu Mono&quot;, monospace !important;\">'<\/code><span style=\"color: rgb(55, 65, 81); font-family: S\u00f6hne, ui-sans-serif, system-ui, -apple-system, &quot;Segoe UI&quot;, Roboto, Ubuntu, Cantarell, &quot;Noto Sans&quot;, sans-serif, &quot;Helvetica Neue&quot;, Arial, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;, &quot;Noto Color Emoji&quot;; font-size: 16px;\">, <\/span><code style=\"border: 0px solid rgb(217, 217, 227); box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-pan-x: ; --tw-pan-y: ; --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; --tw-gradient-from-position: ; --tw-gradient-via-position: ; --tw-gradient-to-position: ; --tw-ordinal: ; --tw-slashed-zero: ; --tw-numeric-figure: ; --tw-numeric-spacing: ; --tw-numeric-fraction: ; --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-shadow: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-shadow-colored: 0 0 transparent; --tw-blur: ; --tw-brightness: ; --tw-contrast: ; --tw-grayscale: ; --tw-hue-rotate: ; --tw-invert: ; --tw-saturate: ; --tw-sepia: ; --tw-drop-shadow: ; --tw-backdrop-blur: ; --tw-backdrop-brightness: ; --tw-backdrop-contrast: ; --tw-backdrop-grayscale: ; --tw-backdrop-hue-rotate: ; --tw-backdrop-invert: ; --tw-backdrop-opacity: ; --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; font-size: 0.875em; color: var(--tw-prose-code); font-weight: 600; font-family: &quot;S\u00f6hne Mono&quot;, Monaco, &quot;Andale Mono&quot;, &quot;Ubuntu Mono&quot;, monospace !important;\">'<\/code><code>YourProjectKey<\/code><code style=\"border: 0px solid rgb(217, 217, 227); box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-pan-x: ; --tw-pan-y: ; --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; --tw-gradient-from-position: ; --tw-gradient-via-position: ; --tw-gradient-to-position: ; --tw-ordinal: ; --tw-slashed-zero: ; --tw-numeric-figure: ; --tw-numeric-spacing: ; --tw-numeric-fraction: ; --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-shadow: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-shadow-colored: 0 0 transparent; --tw-blur: ; --tw-brightness: ; --tw-contrast: ; --tw-grayscale: ; --tw-hue-rotate: ; --tw-invert: ; --tw-saturate: ; --tw-sepia: ; --tw-drop-shadow: ; --tw-backdrop-blur: ; --tw-backdrop-brightness: ; --tw-backdrop-contrast: ; --tw-backdrop-grayscale: ; --tw-backdrop-hue-rotate: ; --tw-backdrop-invert: ; --tw-backdrop-opacity: ; --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; font-size: 0.875em; color: var(--tw-prose-code); font-weight: 600; font-family: &quot;S\u00f6hne Mono&quot;, Monaco, &quot;Andale Mono&quot;, &quot;Ubuntu Mono&quot;, monospace !important;\">'<\/code><span style=\"color: rgb(55, 65, 81); font-family: S\u00f6hne, ui-sans-serif, system-ui, -apple-system, &quot;Segoe UI&quot;, Roboto, Ubuntu, Cantarell, &quot;Noto Sans&quot;, sans-serif, &quot;Helvetica Neue&quot;, Arial, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;, &quot;Noto Color Emoji&quot;; font-size: 16px;\">, and <\/span><code style=\"border: 0px solid rgb(217, 217, 227); box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-pan-x: ; --tw-pan-y: ; --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; --tw-gradient-from-position: ; --tw-gradient-via-position: ; --tw-gradient-to-position: ; --tw-ordinal: ; --tw-slashed-zero: ; --tw-numeric-figure: ; --tw-numeric-spacing: ; --tw-numeric-fraction: ; --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-shadow: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-shadow-colored: 0 0 transparent; --tw-blur: ; --tw-brightness: ; --tw-contrast: ; --tw-grayscale: ; --tw-hue-rotate: ; --tw-invert: ; --tw-saturate: ; --tw-sepia: ; --tw-drop-shadow: ; --tw-backdrop-blur: ; --tw-backdrop-brightness: ; --tw-backdrop-contrast: ; --tw-backdrop-grayscale: ; --tw-backdrop-hue-rotate: ; --tw-backdrop-invert: ; --tw-backdrop-opacity: ; --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; font-size: 0.875em; color: var(--tw-prose-code); font-weight: 600; font-family: &quot;S\u00f6hne Mono&quot;, Monaco, &quot;Andale Mono&quot;, &quot;Ubuntu Mono&quot;, monospace !important;\">'<\/code><code>YourProjectName<\/code><code style=\"border: 0px solid rgb(217, 217, 227); box-sizing: border-box; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-pan-x: ; --tw-pan-y: ; --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; --tw-gradient-from-position: ; --tw-gradient-via-position: ; --tw-gradient-to-position: ; --tw-ordinal: ; --tw-slashed-zero: ; --tw-numeric-figure: ; --tw-numeric-spacing: ; --tw-numeric-fraction: ; --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-shadow: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-shadow-colored: 0 0 transparent; --tw-blur: ; --tw-brightness: ; --tw-contrast: ; --tw-grayscale: ; --tw-hue-rotate: ; --tw-invert: ; --tw-saturate: ; --tw-sepia: ; --tw-drop-shadow: ; --tw-backdrop-blur: ; --tw-backdrop-brightness: ; --tw-backdrop-contrast: ; --tw-backdrop-grayscale: ; --tw-backdrop-hue-rotate: ; --tw-backdrop-invert: ; --tw-backdrop-opacity: ; --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; font-size: 0.875em; color: var(--tw-prose-code); font-weight: 600; font-family: &quot;S\u00f6hne Mono&quot;, Monaco, &quot;Andale Mono&quot;, &quot;Ubuntu Mono&quot;, monospace !important;\">'<\/code><span style=\"color: rgb(55, 65, 81); font-family: S\u00f6hne, ui-sans-serif, system-ui, -apple-system, &quot;Segoe UI&quot;, Roboto, Ubuntu, Cantarell, &quot;Noto Sans&quot;, sans-serif, &quot;Helvetica Neue&quot;, Arial, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;, &quot;Noto Color Emoji&quot;; font-size: 16px;\"> with your actual SonarCloud configuration.<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Commit and Push<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Commit the <code>azure-pipelines.yml<\/code> file to your repository and push the changes. This will trigger the Azure Pipelines to run.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Monitor Pipeline Runs and Iterate<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Azure DevOps Portal:<\/strong><ul><li>Navigate to the Azure DevOps portal and monitor the pipeline runs under the Pipelines section.<\/li><\/ul><\/li>\n\n\n\n<li><strong>Feedback Loop:<\/strong><ul><li>Review the logs and results provided by the pipeline. Address any issues and iterate on your pipeline configuration as needed.<\/li><\/ul><\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion:<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Congratulations! You&#8217;ve successfully set up Azure Pipelines for your .NET project with quality tests and SonarCloud integration. This automated pipeline will help you maintain code quality and streamline the development process. Keep refining and customizing your pipeline based on the specific needs of your project. Happy coding!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the realm of .NET development, establishing a robust CI\/CD pipeline is vital for ensuring code quality and delivering reliable software. Azure Pipelines, part of the Azure DevOps suite, provides a seamless solution for automating build and deployment processes. In this tutorial, we&#8217;ll guide you through the process of setting up Azure Pipelines for a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":116,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21],"tags":[24,23,10,25,26],"class_list":["post-113","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops-and-testing","tag-net","tag-azure-pipelines","tag-how-to","tag-quality-tests","tag-sonarcloud"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/davagordon.co.uk\/blog\/wp-json\/wp\/v2\/posts\/113","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/davagordon.co.uk\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/davagordon.co.uk\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/davagordon.co.uk\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/davagordon.co.uk\/blog\/wp-json\/wp\/v2\/comments?post=113"}],"version-history":[{"count":2,"href":"https:\/\/davagordon.co.uk\/blog\/wp-json\/wp\/v2\/posts\/113\/revisions"}],"predecessor-version":[{"id":115,"href":"https:\/\/davagordon.co.uk\/blog\/wp-json\/wp\/v2\/posts\/113\/revisions\/115"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/davagordon.co.uk\/blog\/wp-json\/wp\/v2\/media\/116"}],"wp:attachment":[{"href":"https:\/\/davagordon.co.uk\/blog\/wp-json\/wp\/v2\/media?parent=113"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/davagordon.co.uk\/blog\/wp-json\/wp\/v2\/categories?post=113"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/davagordon.co.uk\/blog\/wp-json\/wp\/v2\/tags?post=113"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}