About Lint

For teams that have set up CI development environments, code specification management is bound to become the cornerstone of team collaboration. However, adding formatting and specification checks to manual CodeReview presents the following problems

  1. Low technical content, a lot of repetitive work
  2. Prone to misjudgment
  3. Specification changes are difficult to synchronize and maintain

To address these problems, the concept of code Lint was born.

Historical background

Code Lint has a long history compared to other technologies. Lint is a tool used to analyze static source code and detect code specifications and defects. Lint was first used to detect C code in Unix systems.

Usage scenarios

In a real Lint scenario, any tool that is used as a third-party verification aid would be classified as lint. Such as:

The main purpose
commitizen lint Check git commit information specifications
eslint Static detection of JS code specifications and defects
imageSizeLint Check items for abnormal size image detection

Common code Lint libraries

language Lint library
Objective-C OCLint
Swift SwiftLint
java(android) AndroidStudio Lint
kotlin klint
javascript eslint
go golint

The life cycle that Lint can participate in

IDE support

Jetbrain’s IDE family (WebStorm, AndroidStudio, AppCode), VSCode all have rich lint plugins, most of which are based on common lint libraries. The above two ides support almost all other languages except Objective-C. Xcode no longer supports plugins, but you can use Xcode’s auxiliary API to output Lint error logs at compile time, representing OClint and SwiftLint.

Other cycles

In addition to IDE support, the rest of the lifecycle can be implemented using the command-line tools that come with the Lint library.

2. Customize your Own Lint workflow

After reading the introduction above, you might think. Wouldn’t I just integrate Lint in the CI phase and be done with it? There is an analogy here – the difference between SVN and Git. The main one is centralized versus distributed. Going back to the Lint stream, when some Lint checks and piles up the final interception on a PR commit, there are the following problems:

  1. The feedback chain is too long to be monitored until the PR runs CI at the end.
  2. CI single point feedback is influenced by many factors, including network speed, CI machine performance, code integration and so on.
  3. Poor repair experience, unable to do real-time verification for fixed problems. In summary, we need the basisdistributedandThe centralizedThe questions complement each other.

There are also very good practices around the centralized Lint pattern, but the focus is different from the topic discussed in this article and I won’t go into that here.

  1. Lint monitors at different stages of code.
  2. There is a Lint configuration center for rule distribution at each stage.
  3. Multiple REPO projects, centrally managed by the Lint configuration center, especially in back-end microservices, front-end multi-REPO scenarios.
  4. After the final information is collected through CI detection, mail is synchronized through the feedback service, and the quality of each CI integration is reported. Lint quality is considered as a subset of the integration quality.

How to implement iOS Lint stream management

According to the above steps, we need to implement it step by step.

IDE editor practices

For iOS, you have the following options

IDE Type OCLint SwiftLint IDE default lint
Xcode
AppCode
VSCode nonsupport

As mentioned above, with the exception of VSCode not supporting OC, other editors are large and small integrated with the lint environment.

Of these, only AppCode supports real-time feedback on code editing.

IDE Default Lint basically does not support custom rule making, so you can use it with some choice.

Xcode lint integration

The lint checks that Xcode supports are mostly compile-based, so the location where Lint results are viewed is unique and not reflected in real time as code is written, as shown in the figure below.

OCLint integration

The OCLint website provides Use OCLint in Xcode for Xcode integration. And for project-level Lint, you need to follow the compilation for Lint detection.

SwitLint integration

“Use Swift in Xcode” is easier to configure, also project-level, and follows compilation. Pod integration is highly recommended, mainly to reduce the cost of your integration (avoiding Homebrew, path configuration costs), as well as other benefits discussed below in git Lint. But you can use the command line for a single file Lint, as follows.

$ swiftlint lint <source file0> <source file1> ...
Copy the code

default lint

Clang Static Analyzer is a warning and error generated by Xcode during compilation, but lacks code style checking.

AppCode lint configuration

SwiftLint

Use the JetBrain plug-in for integration, as you can see here.

IDE Default lint

VSCode

VSCode only supports plugins for the SwiftLint app market.

IDE lint summary

To sum up, AppCode is preferred for daily code development and Lint feedback, being lightweight and independent of compilation, for uniformity and extensibility.

Compile the lint

In the previous section, IDE Lint is actually used to compile Lint, whether OCLint or SwiftLint is naturally supported, so I won’t go into details here.

Git commits lint

Describe the advantages of doing Lint at this point in time for the longest part of the test.

  1. Only lint minimum range, that is, files submitted from staged sections will have the least number of files and have the best performance.
  2. A common problem with old projects is that the old code does not adapt to the new Lint rules, so that the project Lint will not pass until it ADAPTSIDE lintandCompile the lint.
  3. In addition to having the same distributed performance advantage as the cycle above, CI is also more timely than the feedback cycle, with a per-commit granularity.

So, for our own project, we first integrated Lint at this point in time into the project because of the long adaptation cycle of the old code Lint rule.

Git Lint Flow

Because OCLint configuration is relatively complex, we started with SwiftLint. As shown in the figure above, we need to follow the process to implement these two key points.

  1. Lint environment configuration.
  2. Commit Hook Triggers.

Lint environment configuration

As mentioned in the IDE Lint section above, SwiftLint supports single-file Lint.

$ swiftlint lint <source file0> <source file1> ...
Copy the code

But how to combine it with Git Hook?

Unsurprisingly, you will encounter the following problems:

  1. Git hook is difficult to maintain, so you need to write your own hook script and tell everyone in the group to copy the script to.gitDirectory.
  2. Git hook is written by shell by default, which requires some shell experience.
  3. How to determine which files are to be committed? Although Git provides related commands, you need to do your own event binding with Git hook.
  4. After determining the file to commit, how to jump commit and provide a good hint if Lint fails?

There is basically no relevant practice in iOS, so let’s look at the solutions of other technology stacks.

eslint

So let’s talk about these parts

Git hooks are a node-based trigger that reverses dependencies on git hooks, so that your repo and other configuration centers don’t have to copy and paste. Attached is the Husky Tutorial.

Lint-staged: Mainly responsible for detecting Git files to be submitted and submitting lists to Lint tools. Attached “Lint-Staged Tutorial”

Lint tools: EsLint, SwiftLint and other lint tools.

Hands-on practice

  1. Configure package.json in the project root directory
{"name": "ycMath", "version": "0.0.1", "private": true, "devDependencies": { "^ 2.7.0," "lint - staged" : "^ 8.2.1"}, "husky" : {" hooks ": {" pre - commit" : "Lint-passage" # specifies that pre-commit hooks can be triggered into lint-thrusts}}, "lint-passage ": {"linters": {"*. Swift ":["Pods/SwiftLint/ SwiftLint "] # Install SwiftLint with POD}}}Copy the code
  1. Root NPM install(everyone has NPM installed by default, because 😂 is used too often)
$ npm install
Copy the code

note! Don’t forget to ignore the root directory in the.gitignore filenode_modulesThis folder.

  1. Create a new SWIFT file for verification
$ vim AppDelegate.swift Write a very long comment in the file, such as a 218 character comment.
Copy the code
  1. Get feedback results and commit failed
$ git add .
$ git commit -m "test"Husky > pre-commit (node V8.9.1) ↓ Stashing changes... To be deflated or deflated; to be deflated or deflated → No partially lit files found... ❯ Running linters... ❯ Running tasksfor*. Swift * Pods/SwiftLint/ SwiftLint Lint * Found some errors. Please fix them and try committing again. /Users/chaoyang/Dev/testLint/ Appdelegate. swift ⛔️ Line 27: Line should be 120 characters or less: currently 218 characters ⚠️ Line 40: Line should be 120 characters or less: currently 128 characters ...Copy the code

At this point, your Git Lint link is functional.

Based on theDRYContinue to optimize

After synchronizing these tutorials with the principles, many people forgot about the NPM Install Lint tool or didn’t know how to install it. In line with the DRY principle, try not to repeat anything you can’t. Then I need to solve the following problems:

  1. How to detect if your Lint environment is installed?
  2. If there is a detection scheme, when should it be?
  3. If detected, how to prompt the developer to install?

I started a new round of exploration and finally found inspiration in the article “iOS Development based on CocoapoD”.

  1. Configure your Podfile by adding the following Ruby code
## Lint plugin validation
pre_install do |installer|
  Get the plugin path
  sandbox_root = Pathname(installer.sandbox.root)
  ycroot = File.expand_path("..", sandbox_root)
  node_module_lint_stage = File.expand_path("node_modules/lint-staged/",ycroot)
  node_module_husky = File.expand_path("node_modules/husky",ycroot) has_lint_stage = File.exist? (node_module_lint_stage) has_husky = File.exist? (node_module_husky)# Check whether Lint-staged and Husky are installed
  if has_husky && has_lint_stage
    Pod::UI.puts "Lint and Husky exist, please continue."
  else
    # plan a
    raise "Warning BY @superyang \n\nYCLog error: Lint passage or Husky does not exist use the following command to install: NPM install"

    # This exception may not be very friendly, but if you think everyone has to install NPM locally, you can use plan 2 below
    # 2
    # Pod:: UY. puts "Lint passage and Husky did not exist and are trying to install."
    # 'rm -rf node_modules && NPM install&&echo Lint had been installed successfully'
    # Pod: : UI. Puts "lint staged and husky complete installation 🍺 🍺 🍺 ~ ~ ~"
  end
end
Copy the code
  1. Delete in the root directorynode_modulesDirectory.
$ rm -rf node_modules
Copy the code
  1. Run the pod install or update command.
$ pod install
Copy the code
  1. Viewing Error Messages
# plan a[!]  An error occurredwhileProcessing the pre-install hook of the Podfile. Warning by @superyang YCLog error: Lint passage husky does not exist please install it using the following command: npm installCopy the code
# 2Lint and Husky don't exist, installation is being attempted. Passage Ten Installation of Lint and Husky completed 🍺🍺🍺~~Copy the code

The second scheme is strongly recommended. The extra problems are few, only a few people forget to install NPM on their new computers.

CI Lint configures & Automates Lint reporting

I’ve spent a lot of time on how To play Lint in several scenarios, but I won’t go into details about CI Lint and the feedback reporting process in this article. I’ll test it later in the project and share it with you on the blog once it’s done.

Third, summary

  • Just to review what we know

    1. Based on thedistributedThought of the Lint architecture design.
    2. Lint practices for different life cycles
    3. Design and practice for git Commit Lint link. Git Lint is the lightest process to use and the easiest to automate. For older projects that have not yet adapted lint rules in time, this practice is preferred. File-level detection is also a common lint notch in the industry.
  • Most of the designs above apply to other technology stacks as well.

  • When a problem arises, first accept its inevitability, while trying to take refuge behind closed doors, the same problem, others will certainly encounter, not to shackle themselves to their own technology stack. Embrace the wider community, embrace other technology stacks 😎.

  • Other stacks covered in this article are nodeJS, Ruby, Git, etc.