No report on code quality with Swift project (using SwiftLint tool)

Hello,
I’d like to use SwiftLint tool for linting my iOS projects. As far as I know from both GitLab and CodeClimate documentation I should enable plugin for such tool and then add in GitLab CI some artifacts.

I enabled SwiftLint tool for CodeClimate Engine like this:

    plugins:
       swiftlint:
          enabled: true

Okay, I also added extra job in my gitlab-ci config file:

swiftlint_check:
  dependencies: []
  stage: linting
  artifacts:
    expire_in: 7 days
    paths:
      - fastlane/swiftlint.json
    reports:
      codequality: fastlane/swiftlint.json
  script:
    - fastlane lint
  tags:
    - ios
  only:
    - merge_requests

However and the end of the pipeline on my merge request all I get from report is a message: “Failed to load codeclimate report”.

What I am doing wrong?

@bdolewski - Thanks for posting!

It appears from your post that swiftlint.json file is generated by fastlane, not by the codequality job. If that is the case you need to ensure that swiftlint.json file matches the expected format or the file will not be loaded.

I’d suggest reviewing the docs and especially the troubleshooting section of the documentation for Code Quality.

I’d suggest reviewing the Troubleshooting section of the documentation for Code Quality.

Thanks!

James H
GitLab Product Manager, Verify:Testing

2 Likes

Hi @jheimbuck_gl
Thanks for you explanation! I understand that I have to write my own tool to convert Fastlane output files into something compliant with CodeClimate Engine’s JSON file.

However… not really :slight_smile:

This Fastlane command is just a wrapper for SwiftLint and it produces the same output as SwiftLint used directly.

Let’s say there is no Fastlane in my project, for instance it is macOS only Swift code. I’d have .gitlab-ci.yml file like this:

swiftlint_check:
  dependencies: []
  stage: linting
  artifacts:
     expire_in: 7 days
     paths:
        - some_output_dir/swiftlint.json
  reports:
      codequality: some_output_dir/swiftlint.json
  script:
      - swiftlint
  tags:
      - ios
  only:
      - merge_requests

Shouldn’t be enough for GitLab CI to just grab my output when I also configured .codeclimate.yml to enable SwiftLint plugin? If I still need to provide my own tool for mangling SwiftLint’s outputs to make GitLab CI reports happy, then what’s the point of this plugin ? :slight_smile:

1 Like

@bdolewski - the Code Quality feature in GitLab only supports reading files in the expected format so if the swiftlint.json file isn’t formatted like a codeclimate.json file the GitLab feature will not be able to read it. That seems to be what’s happening here.

re: the .codeclimate.yml this file is used when the Code-Quality.gitlab-ci.yml template is used. Instead of including the swiftlint_check: job you can include that template, keep the modified .codeclimate.yml file in place and after the job runs on your target and source branches you will see the merge request widget on the Merge Request page.

Hopefully this helps clarify for you.

-James H, GitLab Product Manager, Verify:Testing

2 Likes

Hi @jheimbuck_gl

Thank you for your feedback. I’m using gitlab-runner configured as shell runner (it’s a Mac mini machine that I have physical access to) - I don’t know if that an issue for CodeQuality feature since I don’t use docker for iOS/macOS app development.

I written my own conversion script in Python that grabs output from SwiftLint and produces JSON file compliant with CodeQuality format. Here is example of what my tool produced:

[
{
    "description": "Files should have a single trailing newline.",
    "fingerprint": "b82aa8c8-5e34-4c42-afc1-d9b6f6e4db17",
    "location": {
        "lines": {
            "begin": 25
        },
        "path": "app_ios/Repositories/Networking/Requests/Appointment/TimelogRequest.swift"
    }
},
{
    "description": "Colons should be next to the identifier when specifying a type and next to the key in dictionary literals.",
    "fingerprint": "198b1eb2-3867-4014-9542-5d7fd6ba7593",
    "location": {
        "lines": {
            "begin": 17
        },
        "path": "app_ios/Repositories/Networking/Requests/Appointment/SignatureUploadRequest.swift"
    }
}
]

I have modified my .gitlab-ci.yml file this way:

stages:
  - linting
  - testing
  - deploy

variables:
  LC_ALL: "en_US.UTF-8"
  LANG: "en_US.UTF-8"

# I doubt it does anything really
include:
  - template: Code-Quality.gitlab-ci.yml

code_quality:
  dependencies: []
  stage: linting
  artifacts:
    expire_in: 7 days
    paths:
      - fastlane/codequality_report.json
    reports:
      codequality: fastlane/codequality_report.json
  script:
    - fastlane lint
    - python3 codeclimate_converter.py
  tags:
    - ios
  only:
    - merge_requests

This way I got mixed results. One one hand I still cannot see Code Quality widget on my merge requests but I see something like this:

However I can see some report when I go to Pipeline view like this:

I have no idea if my configuration is missing something or it Code Quality widget on Merge Requests simply doesn’t work on shell gitlab-runner but I’m starting to lose hope that GitLab CI + CodeClimate works with Swift language at all.

@bdolewski - It looks like the problem is in the line only: - merge_requests. You’ll have the full report in the pipeline view as you see but no report is being created to compare against when the report is generated in the Merge Request pipeline. This is why you see a report on the pipeline page but no comparison on the MR page.

-James H, GitLab Product Manager, Verify:Testing

I see. Should I simply remove only: - merge_requests or replace it with something like when: always ?
Already tried both ways and my code_quality job was simply missing from merge request stages.

However I changed my entire .gitlab-ci.yml to just remove some jobs to be merge request only. That restriction is not needed in my case.

include:
  - template: Code-Quality.gitlab-ci.yml

code_quality:
  dependencies: []
  stage: linting
  artifacts:
    paths:
      - fastlane/codequality_report.json
    reports:
      codequality: fastlane/codequality_report.json
  script:
    - fastlane lint
    - python3 codeclimate_converter.py
  tags:
    - ios

unit_tests:
  dependencies: []
  stage: testing
  artifacts:
    paths:
      - test_logs/test_report.xml
    reports:
      junit: test_logs/test_report.xml
  script:
    - fastlane unit_tests
  tags:
    - iOS

I still get the Base pipeline codequality artifact not found message :thinking: Maybe because since it finished for the first time there is nothing to compare against like in the video: https://www.youtube.com/watch?v=B32LxtJKo9M

That should do it @bdolewski - now that there is a report for the base further MRs will show that comparison.

Thanks for sticking with it we hope you enjoy the feature!

-James H, GitLab Product Manager, Verify:Testing

After working with Jira for over 5+ years when I had to literally live and breathe Jira - I just love GitLab capabilities :slight_smile: Maybe it’s not so obvious from my post here but I do love GitLab CI as well (and I’m not a dev-ops, just a senior iOS Dev!) . GitLab CI feels like it’s tailored for front-end/Java/C++/whatever development but not that much for mobile projects in Swift or Kotlin (iOS/Android).

Yes, there is a code climate SwiftLint’s plugin - but it’s poorly documented and I doubt it works with gitlab-runner as shell (I think it’s for docker only but I may be wrong).

Anyway - if all the fixes will work - then I’ll post complete configuration for other Swift developers to get out-of-the-box solution :slight_smile:

1 Like

@bdolewski that contribution would be GREATLY appreciated!

I’m glad to hear you are enjoying Gitlab overall and we’d appreciate any further feedback as we continue to build out capabilities for mobile developers!

-James H, GitLab Product Manager, Verify:Testing

Any luck getting this set up? I also want to run Swiftlint on my project and get Code Quality outputs.

Hi @ricky-git, hi @jheimbuck_gl

After all those struggles I can provide some working solution for CodeClimate + SwiftLint for Swift project.

Disclaimer

  • My configuration was created to be compliant with GitLab 12. Now my company (finally!) moved to GitLab 13 (enterprise edition) so some parts of configuration could be deprecated soon.
  • My iOS projects have Merge Train enabled, therefore I had to duplicate quite a lot in my config file since I don’t know any better

Basically you need to plug-in SwiftLint into your pipeline and then you need to convert the SwiftLint output to CodeClimate’s format. I choose to produce SwiftLint’s output as JSON since it’s fairly easy to convert this into CodeClimate’s JSON. To do so I create simple Python script but I believe that SwiftLint could have already GitLab-friendly option to generate output already formatted.

Part I - Fastlane & SwiftLint

I use Fastlane, so my SwiftLint is wrapped by Fastlane like so:

# just a part of Fastfile
lane :lint do
  swiftlint(
      reporter: "json",
      output_file: "fastlane/swiftlint.json"
  )
end

Part II - Python converter

I’m not a super-duper Python coder and I didn’t care that much about hard-coded paths, but please change it as you want :slight_smile:

import json
import sys
import uuid

def convert(issue):
    codeClimateItem = {
        'description': issue["reason"],
        'fingerprint': str(uuid.uuid4()),
        'location': {
        'path': issue["file"],
        'lines': {
            'begin': issue["line"]
            }
        }
    }

    return codeClimateItem

def main(argv):
    print("[CodeClimate Converter] Running the script")
    with open("fastlane/swiftlint.json", "r") as swiftLintData:
        issues = json.load(swiftLintData)

        print("[CodeClimate Converter] Loaded fastlane/swiftlint.json file, converting....")
        convertedIssues = list(map(convert, issues))

        print("[CodeClimate Converter] Converted, writing to file fastlane/codequality_report.json")
        with open("fastlane/codequality_report.json", "w") as codeClimateData:
            json.dump(convertedIssues, codeClimateData, indent=4, sort_keys=True)

if __name__ == "__main__":
   main(sys.argv[1:])

Part III - glue it together with .gitlab-ci.yml

stages:
  - linting
  - testing
  - deploy

variables:
  LC_ALL: "en_US.UTF-8"
  LANG: "en_US.UTF-8"

before_script:
  - git config user.email "gitlab-ci@mycompany.com"
  - git config user.name "GitLab CI"

include:
  - template: Code-Quality.gitlab-ci.yml

code_quality:
  dependencies: []
  stage: linting
  artifacts:
    paths:
      - fastlane/codequality_report.json
    reports:
      codequality: fastlane/codequality_report.json
  script:
    - fastlane lint
    - python3 codeclimate_converter.py
  tags:
    - ios

code_quality_on_merge_request:
  dependencies: []
  stage: linting
  artifacts:
    paths:
      - fastlane/codequality_report.json
    reports:
      codequality: fastlane/codequality_report.json
  script:
    - fastlane lint
    - python3 codeclimate_converter.py
  tags:
    - ios
  only:
    - merge_requests

unit_tests:
  dependencies: []
  stage: testing
  artifacts:
    paths:
      - test_logs/test_report.xml
    reports:
      junit: test_logs/test_report.xml
  script:
    - fastlane unit_tests
  tags:
    - ios

unit_tests_on_merge_request:
  dependencies: []
  stage: testing
  artifacts:
    paths:
      - test_logs/test_report.xml
    reports:
      junit: test_logs/test_report.xml
  script:
    - fastlane unit_tests
  tags:
    - ios
  only:
    - merge_requests

deploy_to_test_flight:
  dependencies: []
  stage: deploy
  artifacts:
    paths:
      - fastlane/screenshots
      - fastlane/logs
  script:
    - fastlane deploy
  tags:
    - ios
  when: manual

@ricky-git As you can see I duplicated some jobs. That’s because when everything was set up to be only: merge_requests then no CodeClimate report was visible because it has to be stored in between jobs (se my previous discussion with @jheimbuck_gl).
If I removed all the merge_requests then Merge Train stopped to work :confused:

@jheimbuck_gl would you like to have some feedback about my ugly duplication? Is there anything from GitLab 13 that I can use to have just 1 jobs that will make CodeClimate widget and Merge Train happy at the same time?

Hey @bdolewski ,
I specified codeclimate as reporter type in swiftlint action.
This way, I didn’t need to use the Python Converter.

# just a part of Fastfile
lane :lint do
  swiftlint(
      reporter: "codeclimate",
      output_file: "./fastlane/swiftlint.json"
  )
end

I didn’t find a solution for the duplication either. If I remove the job that contains only: merge_requests , I don’t get any widget shown in MR anymore.

Hi @raph !
Yes, this Python script is not needed anymore. I created it before SwiftLint added support to generate report compliant with CodeQuality Engine :wink: Also if you use fastlane you can use SwiftLint via fastlane as well (so you have everything in your Fastfile)

Hi @bdolewski , very thank for your solution, may i check one question with you → Did your team create the script within the Xcode to run swiftLint when building project every time? If so, when the project running at CI, how to disable the script?