├── README.md └── lint-up.rb /README.md: -------------------------------------------------------------------------------- 1 | DEPRECATED; The built in "baseline" generator has gotten so good that this script isn't helpful. See [Create Warnings Baseline](https://developer.android.com/studio/write/lint.html) 2 | 3 | # Android Lint Entropy Reducer 4 | 5 | Over time Lint errors and warnings build up in a project. It's a daunting task to remove all of these errors at once. It's also not very helpful to fix a bunch of errors if more keep cropping up over time. By including this script as part of your build process, you can always ensure that the number of Lint errors and warnings never rises above current levels. Any reduction in errors or warnings count will be preserved. This will trend the number of Lint errors/warnings to zero. 6 | 7 | ## First Time Setup 8 | 0. ensure that Travis is set to "build pull requests" 9 | 1. create new branch 10 | 2. include this script in project and set executable `chmod +x lint-up.rb` 11 | 3. update `travis.yml` (see below) 12 | 4. setup script parameters (see below) 13 | 4. commit changes 14 | 5. push new branch to origin 15 | 6. open PR against new branch 16 | 7. The script will run and create a baseline of existing error/warning count 17 | 8. merge new branch into master 18 | 19 | Now any new pull requests will have to maintain or reduce the number of Lint errors/warnings. 20 | 21 | 22 | ## Update Travis.yml 23 | 24 | Include this script in your `travis.yml` file: 25 | 26 | ``` 27 | script: 28 | - ./gradlew clean assembleDebug 29 | - ./gradlew clean test 30 | - ruby scripts/lint-up.rb 31 | ``` 32 | 33 | You are encouraged to place this script in a separate directory (here called `scripts`). It also makes sense to run Lint *after* assemble and test. There is no point in running Lint checks if your app isn't compiling and passing tests. 34 | 35 | Because any increase in Lint errors/warnings should fail the build, you need to call this script from the `script` stage. Read more about breaking Travis builds [here](http://docs.travis-ci.com/user/customizing-the-build/#Breaking-the-Build). 36 | 37 | ## Script Parameters 38 | 39 | At the top of the lint-up.rb file is a list of user-adjustable parameters that define the behavior of the script. Defaults have been set so that you don't **have** to make any changes. 40 | 41 | #### TRAVS_GIT_USERNAME 42 | 43 | At some point, if the number of errors or warnings decreases, this script will create a new git commit with updated results. These results will become the new baseline for future checks. This parameter will set the git username used by the script. 44 | 45 | 46 | ``` 47 | # User name for git commits made by this script. 48 | TRAVS_GIT_USERNAME="Travis CI server" 49 | ``` 50 | 51 | #### LINT_REPORT_FILE 52 | 53 | In your build.gradle file, you set where the generated Lint report should be saved. This script needs access to that file. 54 | 55 | 56 | ``` 57 | # File name and relative path of generated Lint report. 58 | # Must match build.gradle file: 59 | # lintOptions { 60 | # htmlOutput file("[FILE_NAME].html") 61 | # } 62 | LINT_REPORT_FILE="app/lint-report.html" 63 | ``` 64 | 65 | #### PREVIOUS_LINT_RESULTS_FILE 66 | 67 | This script will generate a baseline report file that represents the current error/warning count. This file's contents will be updated as the error/warning count is reduced. You should not move this file after beginning using this script. If you do, be sure to update this setting. 68 | 69 | ``` 70 | # File name and relative path of previous results of this script. 71 | PREVIOUS_LINT_RESULTS_FILE="lint-report/lint-results.xml" 72 | ``` 73 | 74 | #### CHECK_WARNINGS 75 | 76 | This script can perform separate reduction checks for errors as well as warnings. If you choose to ignore warnings in your build.gradle file, you can choose to ignore warnings in this script (and only track errors). 77 | 78 | ``` 79 | # Flag to evaluate warnings. true = check warnings; false = ignore warnings 80 | CHECK_WARNINGS=true 81 | ``` 82 | 83 | #### CUSTOM_LINT_FILE 84 | 85 | This script can also run custom Lint rules. They need to be included in a separate .jar. Read more [here](https://engineering.linkedin.com/android/writing-custom-lint-checks-gradle) and [here](http://tools.android.com/tips/lint-custom-rules). This parameter can be left blank (either nil or an empty string) 86 | 87 | ``` 88 | # File name and relative path to custom lint rules; Can be nil or "". 89 | CUSTOM_LINT_FILE="lint_rules/lint.jar" 90 | ``` 91 | -------------------------------------------------------------------------------- /lint-up.rb: -------------------------------------------------------------------------------- 1 | puts "=================== starting Android Lint Entropy Reducer ====================" 2 | 3 | # ======================== SETUP ============================ 4 | 5 | # User name for git commits made by this script. 6 | TRAVIS_GIT_USERNAME = String.new("Travis CI server") 7 | 8 | # File name and relative path of generated Lint report. Must match build.gradle file: 9 | # lintOptions { 10 | # htmlOutput file("[FILE_NAME].html") 11 | # } 12 | LINT_REPORT_FILE = String.new("app/lint-report.html") 13 | 14 | # File name and relative path of previous results of this script. 15 | PREVIOUS_LINT_RESULTS_FILE=String.new("lint-report/lint-results.txt") 16 | 17 | # Flag to evaluate warnings. true = check warnings; false = ignore warnings 18 | CHECK_WARNINGS = true 19 | 20 | # File name and relative path to custom lint rules; Can be null or "". 21 | CUSTOM_LINT_FILE = String.new("") 22 | 23 | # ================ SETUP DONE; DON'T TOUCH ANYTHING BELOW ================ 24 | 25 | require 'fileutils' 26 | require 'pathname' 27 | require 'open3' 28 | 29 | # since we need the xml-simple gem, and we want this script self-contained, let's grab it just when we need it 30 | begin 31 | gem "xml-simple" 32 | rescue LoadError 33 | system("gem install xml-simple") 34 | Gem.clear_paths 35 | end 36 | 37 | require 'xmlsimple' 38 | 39 | # add custom Lint jar 40 | if CUSTOM_LINT_FILE != nil && 41 | CUSTOM_LINT_FILE.length > 0 42 | 43 | ENV["ANDROID_LINT_JARS"] = Dir.pwd + "/" + CUSTOM_LINT_FILE 44 | puts "adding custom lint rules to default set: " 45 | puts ENV["ANDROID_LINT_JARS"] 46 | end 47 | 48 | # run Lint 49 | puts "running Lint..." 50 | system './gradlew clean lint' 51 | 52 | # confirm that Lint ran w/out error 53 | result = $?.to_i 54 | if result != 0 55 | puts "FAIL: failed to run ./gradlew clean lint" 56 | exit 1 57 | end 58 | 59 | # find Lint report file 60 | lint_reports = Dir.glob(LINT_REPORT_FILE) 61 | if lint_reports.length == 0 62 | puts "Lint HTML report not found." 63 | exit 1 64 | end 65 | lint_report = String.new(lint_reports[0]) 66 | 67 | # find error/warning count string in HTML report 68 | error_warning_string = "" 69 | File.open lint_report do |file| 70 | error_warning_string = file.find { |line| line =~ /[0-9]* errors and [0-9]* warnings/ } 71 | end 72 | 73 | # find number of errors 74 | error_string = error_warning_string.match(/[0-9]* errors/)[0] 75 | current_error_count = error_string.match(/[0-9]*/)[0].to_i 76 | puts "found errors: " + current_error_count.to_s 77 | 78 | # find number of warnings 79 | if CHECK_WARNINGS == true 80 | warning_string = error_warning_string.match(/[0-9]* warnings/)[0] 81 | current_warning_count = warning_string.match(/[0-9]*/)[0].to_i 82 | puts "found warnings: " + current_warning_count.to_s 83 | end 84 | 85 | # get previous error and warning counts from last successful build 86 | 87 | previous_results = false 88 | 89 | previous_lint_reports = Dir.glob(PREVIOUS_LINT_RESULTS_FILE) 90 | if previous_lint_reports == nil || 91 | previous_lint_reports.length == 0 92 | 93 | previous_lint_report = File.new(PREVIOUS_LINT_RESULTS_FILE, "w") # create for writing to later 94 | else 95 | previous_lint_report = String.new(previous_lint_reports[0]) 96 | 97 | previous_error_warning_string = "" 98 | File.open previous_lint_report do |file| 99 | previous_error_warning_string = file.find { |line| line =~ /[0-9]* errors and [0-9]* warnings/ } 100 | end 101 | 102 | unless previous_error_warning_string.nil? 103 | previous_results = true 104 | 105 | previous_error_string = previous_error_warning_string.match(/[0-9]* errors/)[0] 106 | previous_error_count = previous_error_string.match(/[0-9]*/)[0].to_i 107 | puts "previous errors: " + previous_error_count.to_s 108 | 109 | if CHECK_WARNINGS == true 110 | previous_warning_string = previous_error_warning_string.match(/[0-9]* warnings/)[0] 111 | previous_warning_count = previous_warning_string.match(/[0-9]*/)[0].to_i 112 | puts "previous warnings: " + previous_warning_count.to_s 113 | end 114 | end 115 | end 116 | 117 | # compare previous error count with current error count 118 | if previous_results == true && 119 | current_error_count > previous_error_count 120 | puts "FAIL: error count increased" 121 | exit 1 122 | end 123 | 124 | # compare previous warning count with current warning count 125 | if CHECK_WARNINGS == true && 126 | previous_results == true && 127 | current_warning_count > previous_warning_count 128 | 129 | puts "FAIL: warning count increased" 130 | exit 1 131 | end 132 | 133 | # check if warning and error count stayed the same 134 | if previous_results == true && 135 | current_error_count == previous_error_count && 136 | current_warning_count == previous_warning_count 137 | 138 | puts "SUCCESS: count stayed the same" 139 | exit 0 140 | end 141 | 142 | # either error count or warning count DECREASED 143 | 144 | # write new results to file (will overwrite existing, or create new) 145 | File.write(previous_lint_report, "DO NOT TOUCH; GENERATED BY TRAVIS\n" + error_warning_string) 146 | 147 | # push changes to github (if this script is run locally, we don't want to overwrite git username and email, so save temporarily) 148 | previous_git_username, st = Open3.capture2('git config user.name') 149 | previous_git_username = previous_git_username.strip 150 | 151 | previous_git_email, st = Open3.capture3('git config user.email') 152 | previous_git_email = previous_git_email.strip 153 | 154 | # update git user name and email for this script 155 | system ("git config --local user.name '" + TRAVIS_GIT_USERNAME + "'") 156 | system ("git config --local user.email '.'") # set email blank 157 | 158 | # add previous Lint result file to git 159 | system ('git add ' + PREVIOUS_LINT_RESULTS_FILE) 160 | 161 | # Travis has git in a detached head here. Let's get on the right branch. 162 | travis_branch_name = ENV['TRAVIS_BRANCH'] 163 | if travis_branch_name != nil 164 | system ('git checkout ' + travis_branch_name) 165 | end 166 | 167 | # commit changes; Add "skip ci" so that we don't accidentally trigger another Travis build 168 | system ('git commit -m "Travis: update Lint results to reflect reduced error/warning count [skip ci]" ') 169 | 170 | # push to origin 171 | system("git config push.default simple") 172 | system ("git push") 173 | 174 | # restore previous git user name and email 175 | system("git config --local user.name '#{previous_git_username}'") 176 | system("git config --local user.email '#{previous_git_email}'") 177 | 178 | puts "SUCCESS: count was reduced" 179 | exit 0 # success --------------------------------------------------------------------------------