Part 2: Automating code quality scanning using Sonar Cloud and GitHub Actions
Tags: sonarcloud, github, codequality, git
Published: 2021-08-09 16:58:29

[Part 1 of our article](https://dev.to/jeiman/part-1-concepts-of-code-quality-in-sonar-cloud-318j) talks about the fundamentals of code quality with respect to Sonar Cloud. However, these are generic terms that can be applied to any code quality tool. In this article, we will explain how we can use Sonar Cloud to automate our code quality scanning with our GitHub repositories using GitHub Actions. The goal of this article is to ensure that you have a good understanding of how Sonar Cloud performs code analysis, how the integration features on GitHub (PR decorators, inline commenting, code quality overview using widgets) will benefit your engineering teams in the long run.

Some of the neat features that I found Sonar Cloud provides is:

- Enhances your workflow with continuous code quality and code security
- Supports all major programming languages you can think of
- Provides a clear overview of your overall code health in your repository, pull requests and pipelines
- Works with all famous Git providers (GitHub, Bitbucket, Azure DevOps and GitLab)
- Works with all famous CI/CD tools (GitHub Actions, Bitbucket Pipelines, Azure Pipelines, GitLab CI/CD, CircleCI, TravisCI, etc)
- Bug, Vulnerability, and Code Smell detection
- Top-notch coding rules
- In-ALM pull request feedback
- Go/No Go Quality Gate checks
- Automatic analysis (Currently limited to GitHub repositories)

## Preliminaries

You will need the following:

- A GitHub repository with a backend or frontend application
- Access to GitHub Actions
- A Sonar Cloud account
- A Sonar Cloud project
- Some basic knowledge on CI/CD

## Setup Process

### 1. Sign up and import repositories

1. Ensure you have a GitHub repository readily available. For this, we will be choosing one of my NodeJS backend applications.
2. Signup for a Sonar Cloud account and log in using your GitHub account to have a seamless experience.
3. Once you have signed up, you will be redirected to this page:

    ![SetupSonarCloud](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e3ow6qlwzxums4x8xmc1.png)

4. From this page, you can import an organisation from GitHub.
5. Click on **Import an organisation from Github**. 
6. You will be redirected to your GitHub account where it will prompt you to choose an organisation to install SonarCloud. In this article, we will be choosing my own personal GitHub repository.

    ![Connect Sonar Cloud App with GitHub](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h3il28988u9m07e8phns.png)

7. From there, you will be redirected back to Sonar Cloud, where you will create your Sonar Cloud organisation. Please note that at this point, you have already **installed and connected the Sonar Cloud App on your GitHub account**.

    ![Setup project key](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z1xvip96asaopk4m540i.png)

8. From the image above, you can provide an organisation key that will be used later in GitHub Actions to send your code analysis metrics.

    ![Choose pricing plan](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/78cupxpkimwuk7tocf4k.png)

9. Next, you would need to choose a Pricing plan. There are 2 options: **Paid** and **Free**. For this article, we will be choosing the **Free** plan.
10. Click **Create Organization**.
11. You will now be able to import any **Public repository**. If you have Paid for Sonar Cloud, you may import your Private repositories.

    ![Choose your repos](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2wtmf6qib10xozdlodq4.png)

12. We have selected our public repository, named `nodejs-backend-starter`. This repository contains a very basic Node.js backend application with Unit Testing and Code Coverage setup.
    - NOTE: There's also an option to set up a monorepo. Based on the image above, you may see a small section at the bottom right of the image that mentions setting up a monorepo.
13. Once you have selected your repositories, click **Set Up**.
14. It will do an Automatic Analysis of your project providing an initial analysis of it.
15. Although Sonar Cloud offers automatic analysis for GitHub repositories only, we will be **disabling this option** as we want our CI pipeline to handle the analysis process for us. With the CI pipeline, you may replicate this entire process for any Git provider and any CI/CD tool available.
16. Navigate to Administration > Analysis Method > SonarCloud Automatic Analysis. Turn off this option.

    ![Turn off automatic analysis](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r53fneim5wdb5stxffgf.png)

17. Navigate back to your project root page. Your project page should look something like the image below:

    ![Project page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4g2oqzq6smkyxrx8z7oc.png)

18. As you can see, it states that they can't display any Quality Gate without a New Code definition. Based on the [Part 1 article](https://dev.to/jeiman/part-1-concepts-of-code-quality-in-sonar-cloud-318j), we will be setting up the following:
    1. A New Code Definition
    2. A Quality Gate

### 2 Sonar Cloud Configuration

#### 2.1 Set Up New Code definition

There are 2 options available at this moment. You can either set up a New Code definition on:

- A project level
- An organisation level

For this article, we will set it up on a project level.

1. On your project page, click on **Set New Code definition**. If that is not available, you may navigate to **Administration > New Code**.

    ![New Code Definitions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4zwnnxjqhkarjmj68t2s.png)

1. If you have read my previous article, you may know that there are a number of options to choose from. In this case, we will be choosing the **Number of days** that equates to **30 days** by default. The reason is we are not going to be maintaining a version for the project on Sonar Cloud for now.

### 2.2 Setup a Quality Gate

1. Navigate to your organisation page ([https://sonarcloud.io/organizations/{username}/projects](https://sonarcloud.io/organizations/jeimanjeya/projects)).
2. Select **Quality Gates** from the sub-navigation.

    ![Quality Gate Summary](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yu2d9fj6rzwcymvn8tgs.png)

1. From the image above, there's already a default Quality Gate set up for you. We're going to be cloning this and creating our own. Click on **Copy** on the **Sonar way** Quality Gate**.**
2. Name your new cloned Quality Gate.
3. Since there are already New Code conditions, we are simply appending **Overall Code conditions**. For this article, we have added the following:
    1. Coverage is less than 80%
    2. Duplicated Lines is greater than 5%
    3. Maintainability Rating is worse than A
    4. Reliability Rating is worse than A
    5. Security Rating is worse than A

    ![Final Quality Gate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2k3uqjdan2n714y6a3yw.png)

4. Set your new Quality Gate as **Default**.
5. Now that we have our project settings in place, we need to set up a project properties file next. 

### 2.3 Setup a project properties file

This properties file will enable the CI pipeline to perform the necessary configuration and filtering in order to perform the code analysis. Furthermore, this will ensure we have the right settings in place when we push our commit to a branch or create a pull request that triggers the code analysis.

1. In your code repository, create a `sonar-project.properties` file.

```yaml
sonar.exclusions=**/*.bin
sonar.organization=jeimanjeya
sonar.projectKey=jeiman_nodejs-backend-starter
sonar.projectName=jeiman_nodejs-backend-starter
sonar.projectVersion=1.0
sonar.sourceEncoding=UTF-8
sonar.sources=src
sonar.exclusions=node_modules/**
sonar.test.inclusions=test/**
sonar.typescript.lcov.reportPaths=coverage/lcov.info
```

In this file, we're basically narrowing the focus of the scanner to configure the project source path, unit test inclusion path, coverage report path and exclude redundant folder paths (node_modules).

2. Commit this file to your:
- **Root directory**: If it is a single application repository (microrepo) architecture (the case for us)
- **Monorepo directory:** If you have a monorepo architecture

Now that we have set up our project configuration and settings, we can focus on configuring the CI pipeline on GitHub Actions.

### 3. GitHub Actions

#### 3.1 Pipeline/Workflow Structure

You have several to choose from options:

1. Store all of your workflows in a single YAML file - `ci.yml`
2. Separate them into branch workflows:
    1. `ci_develop.yml` - for PR triggers and branch triggers on `develop` branch
    2. `ci_master.yml` - for PR triggers and branch triggers on `main` branch
3. Separate them into trigger workflows:
    1. PR triggers - `ci_pr.yml`
    2. Branch triggers - `ci_branch.yml`
4. Separate them into monorepo workflows:
    1. `spa-frontend.yml` and `ms-backend.yml` - contains PR and branch triggers for both `develop` and `main` branch 

- Option 1 is difficult the maintain in the long run if you follow a monorepo architecture
- Option 2 or 3 is the best way of maintaining your workflows on GitHub
- Option 4 is useful for when you have a monorepo architecture

For this article, we are choosing Option 3 for simplification.

1. Your final GitHub workflow for branch analysis will look like this:

```yaml
name: Sonar Cloud - Branch Analysis

# Controls when the action will run. Triggers the workflow on push
# events but only for the main and release-* branch
on:
  push:
    branches: 
      - main
      - release-*

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  sonarcloud:
    name: Build (Sonar Cloud)
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
      with:
        # Disabling shallow clone is recommended for improving relevancy of reporting
        fetch-depth: 0
    - uses: actions/setup-node@v2
      with:
        node-version: '15'

    - name: Node install dependencies
      run: npm install

    - name: Run unit tests
      run: npm run test
    
    - name: SonarCloud Scan
      uses: sonarsource/sonarcloud-github-action@master
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
```

1. We have included an Action from GitHub Actions and that is the Sonar Cloud Scanner. 
2. In order for Sonar Cloud Scanner to authenticate and upload the analysis reports and metrics, you will need to store the `SONAR_TOKEN` secret in your GitHub repository.
3. Navigate to your project settings and retrieve the project token, **Project > Administration > Analysis Method > Analyze with a GitHub Action**. It will present you with a token.
4. Navigate back to your repository settings on GitHub, **Repository Settings > Secrets > New repository secret**. Name it as per the workflow secret name.
5. For the `GITHUB_TOKEN`, GitHub automatically appends the token for each workflow that runs on GitHub.
6. Commit your code into the `main` branch and watch the pipeline run.

    ![Pipeline logs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4vaq6l5hqw422eofsbxx.png)

    ![Pipeline summary](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3quqvnmruwf2ieu846ky.png)

7. The [summary for the branch analysis pipeline](https://github.com/jeiman/nodejs-backend-starter/runs/3281611957?check_suite_focus=true) has indicated that the analysis was successful.

Navigating back to Sonar Cloud, you will notice that your project branch analysis report has been updated.

![QG Check on branch analysis](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yhiu5gkt9ad2s6yuea04.png)

We'll move on to running code analysis on a long-living branch next.

#### 3.2 Running code analysis on a long-living branch

1. Simply check out a new branch from `main` and name it to `release-{anyname}`
2. Commit your code and the CI pipeline will pick it up based on the branch trigger logic in the workflow YAML file.
3. The SC Scanner will upload your analysis reports to your project on Sonar Cloud.

    ![Not computed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5lli3nisr50f9qfz2ing.png)

4. Don't be alarmed if it shows **Not computed** as Sonar Cloud requires a second analysis to be able to show your Quality Gate on that long-living branch. It mentions **Next scan will generate a Quality Gate**.

    ![Not computed 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6s5gcs03colftir0oxm8.png)

5. We pushed another commit to the repository to the long-living branch to show the Quality Gate.

Your final Quality Gate for branch analysis (on long-living branch) will produce the following result.

![Branch analysis on long-living branch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v8tmckdymgvjqgwsiv5j.png)

#### 3.3 Running code analysis on pull requests (PR)

1. Clone the `ci_branch.yml`. Name it `ci_pr.yml`
2. The only section we are changing is the event trigger. Instead of a `push` event, we are using the `pull_request` event.

```yaml
on:
  pull_request:
    branches:
      - main
      - release-*
```

3. Commit the code and raise a PR in your code repository.

Your PR page should produce pipeline status checks alongside SonarCloud Code Analysis on your Merge PR section. Furthermore, your PR will contain decorations provided by the SonarCloud Bot.

![PR summary report on GitHub](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3hpvek6sl9w6a32b6nt.png)

Your [PR status checks details page](https://github.com/jeiman/nodejs-backend-starter/pull/1/checks?check_run_id=3281994837) should give you a better overview of what needs fixing.

If you navigate back to your Sonar Cloud project and choose your PR analysis report from the branch dropdown menu, you will see similar statistics that were displayed on GitHub.

![PR analysis on Sonar Cloud](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h7qaf2496go3iifootil.png)

Let's go ahead and fix our code to ensure we don't have any code smells and fine tune our Quality Gate conditions to match with a Passed state.

![Passed state](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kjyqdq9gkhnpksm0smmf.png)

Now our PR has clean code (however overall code requires fixes), we can now merge our PR. The pipeline will run another branch analysis on the `main` branch, which is our default branch on Sonar Cloud.

## Piecing it all together

We have accomplished having a Sonar Cloud project connected to a GitHub repository that has GitHub Actions workflows in place to automate our code analysis for branch and PR triggers. Once these analyses are completed on the pipeline, you can navigate back to your Sonar Cloud project and view branch and PR analysis on both your main branch and long-living branches.

One of the plus points in having integration between GitHub and Sonar Cloud is that engineering teams can benefit from having decorations forming up in their pull requests and repository. This will speed up the developer's productivity in fixing bugs, code smells, and vulnerabilities and avoid having further technical debts in their projects.

## Tips

- You can use any CI/CD tools to perform your code analysis. It does not need to be with GitHub Actions even though your repository resides on GitHub, however, for consistency you can keep them all under one umbrella.
- To have a complete end-to-end experience for your code quality scans on your pull requests, ensure you connect and import repositories from one unique Git organisation. The aforementioned features mainly work for that reason. Try not to mix and match repositories from different organisations (even though it's possible to do so).
    - 1 GitHub organisation = 1 Sonar Cloud subscription
    - 1 Azure DevOps organisation = 1 Sonar Cloud subscription
- Create long-living branches on Sonar Cloud if you're following Git flow technique of `develop` and `master` branch. You may read up on their [community post](https://community.sonarsource.com/t/how-to-create-long-living-branches-on-sonarcloud/11386) on how to achieve this. This will ensure that you are performing branch analysis on them alongside your pull request analysis.
- Fine-tune your Quality Gate to ensure you get the best experience from it that matches your engineering teams needs
- Sonar Cloud supports monorepo projects!

I hope this 2-part series has been beneficial and helpful to your engineering needs. Sonar Cloud is a powerful code analysis tool. Please do explore their documentation to find out more or kindly reach out to me for any assistance.

## Demo links to this article

- [Sonar Cloud project](https://sonarcloud.io/dashboard?id=jeiman_nodejs-backend-starter)
- [GitHub repository](https://github.com/jeiman/nodejs-backend-starter)
- [GitHub Actions](https://github.com/jeiman/nodejs-backend-starter/actions)
- [Long-living branch analysis](https://sonarcloud.io/dashboard?branch=release-testsonarcloud&id=jeiman_nodejs-backend-starter)

## References

- [https://docs.microsoft.com/en-us/power-platform/alm/overview-alm](https://docs.microsoft.com/en-us/power-platform/alm/overview-alm)
- [https://sonarcloud.io/github](https://sonarcloud.io/github)