SonarCloud: Fixing unexpected unknown at-rule @tailwind

I'm a big fan of using SonarCloud. Not only does it help to maintain the quality of your projects but the error descriptions are good enough to provide a nice training aspect to developers.

However at some point your going to receive bug reports for things that just aren't bugs.

For example if you are using Tailwind, you may get a Unexpected unknown at-rule "@tailwind" bug reported if you use @tailwind in your code.

Unexpected unknown at-rule "@tailwind"

You know your code is correct, it's just that SonarCloud doesn't know about Tailwind.

Fortunately Sonar allows you to extend all of the built in rules so that you can add customizations to work around things like this.

Fixing unexpected unknown at-rule @tailwind in Sonar

In Sonar, go to the Quality Profiles section.

The Quality Profiles screen lists out to collections of rules which are applied during analysis. From here you can make completely new collections, extend collections and change the defaults ones. With multiple profiles configured you could even have different collections per project.

Filter by the language CSS and then use the settings menu at the end of the Sonar way profile to extend the profile.

Sonar Cloud Quality Profiles screen filtered to CSS

Your new profile will appear under the Sonar way one. Now set it as the default using the settings drop down again. From now on our extended profile will be used during analysis and because its an extension of the Sonar Way, we haven't lost any existing rules. Equally as new rules are added to the default, our extended profile will pick these up too.

Sonar quality profile, set as default.

To update the rule causing unexpected unknown at-rule @tailwind go to the Rules section and filter by CSS.

Sonar CSS Rules

Pick the rule that needs updating. In our case this is "at-rules" should be valid.

At the bottom of this page you will see our Extended profile and the Sonar way profile.

Sonar Rule profile

Click the change button on the Extended profile.

You will get the rule definition. Simply add tailwind to this list of values.

Sonar Edit Rule

Once you save, the profiles on the rules will show that the extended rule has been changed.

Sonar rule updated

That's it. Now when your analysis next runs your extended profile will be used and @Tailwind in your code will no longer fail the at-rule.

SonarQube for .NET Framework with GitHub Actions

If you haven't tried SonarQube or SonarCloud out then I suggest you do. The cloud version is quite straightforward to setup and from my experience the stuff it finds can be quite insightful. Like all these tools, at times you'll disagree with what they say, but there's always the option to change the rules.

What I particularly like with SonarQube is the examples you get with each bug that clearly explains why there's an issue and what you need to do in order to fix it.

What I didn't like however were the instructions for setting a project using .NET Framework. There are instructions labelled .NET, but this heavily assumes your using .NET Core, which while that might be our general preference, products like Sitecore could force your hand back to .NET Framework and all those legacy projects didn't just go away.

How to setup SonarQube using GitHub Actions for .NET Framework

The GitHub setup instructions ( will give you the following code to create your GitHub Action with. This is also the same code you will get if you follow the wizard in SonarQube.

name: Build
    - master # or the name of your main branch
  types: [opened, synchronize, reopened]
  name: Build
  runs-on: windows-latest
    - name: Set up JDK 11
      uses: actions/setup-java@v1
        java-version: 1.11
    - uses: actions/checkout@v2
        fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
    - name: Cache SonarQube packages
      uses: actions/cache@v1
        path: ~\sonar\cache
        key: ${{ runner.os }}-sonar
        restore-keys: ${{ runner.os }}-sonar
    - name: Cache SonarQube scanner
      id: cache-sonar-scanner
      uses: actions/cache@v1
        path: .\.sonar\scanner
        key: ${{ runner.os }}-sonar-scanner
        restore-keys: ${{ runner.os }}-sonar-scanner
    - name: Install SonarQube scanner
      if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
      shell: powershell
      run: |
        New-Item -Path .\.sonar\scanner -ItemType Directory
        dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner
    - name: Build and analyze
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}  # Needed to get PR information, if any
      shell: powershell
      run: |
        .\.sonar\scanner\dotnet-sonarscanner begin /k:"example" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /"${{ secrets.SONAR_HOST_URL }}"
        dotnet build
        .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"

There's two aspects to notice with this. Firstly the Build and analyze section is running a command dotnet build which is fine if your running .Net Core, but for .Net Framework it isn't going to work.

Secondly it's highly likely your solution will use NuGet packages and there's no step in here to restore them.

To setup and restore NuGet packages add in the following steps before the Build and analyze step. Be sure to put your solution filename in the restore command.

      - name: Setup Nuget
      uses: Nuget/setup-nuget@v1.0.5

    - name: Restore nuget packages
      run: nuget restore MySolution.sln

To do a build that will compile your .Net Framework code you will need to use MsBuild rather than dotnet. However if you just swap them over you'll get an invalid command error. First you need to add msbuild to PATH. Change your build steps as follows.

      - name: Add msbuild to PATH
      uses: microsoft/setup-msbuild@v1.0.2

    - name: Build and analyze
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}  # Needed to get PR information, if any
      shell: powershell
      run: |
        .\.sonar\scanner\dotnet-sonarscanner begin /k:"example" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /"${{ secrets.SONAR_HOST_URL }}"
        dotnet build
        .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"

With that now in place you can now compile some .Net Framework code and have the results sent back to your SonarQube instance.

Exporting a Database from SQL Azure

If you need to copy your SQL Azure database locally then exporting it as a Bacpac file is the simplest route to go.

There's many ways you can do this including PowerShell, REST API, and even SQL Server Management Studio. However I am going to show you how to do it through the Azure Portal.

Exporting a Bacpac file

First off find your DB in the Azure Portal.

In the top set of buttons when you view your DB (make sure you're on the actual DB not the server), you will see an export button 3rd from the left.

Clicking Export takes you to a page where you need to configures the filename to export as, the storage account to export to and the authentication to log into the DB. The storage account is required as a place for the export to be saved, you will get the choice of configuring the container for it to go into, so I like to create one called backups.

Checking the status of the export

When you start the export you will get a confirmation that it has started, but knowing how to check what the progress is isn't obvious.

To check the progress, navigate to the DB server in the portal.

In the left nav, under Data management, select Import/Export history.

From here you can view the status of each of the exports.

Once they are complete you can download them through blob storage.