2020-07-07 12:19:21 +00:00
name : Linter
on : [ push, pull_request]
jobs :
lint :
# it's easiest if it matches the version that was used to build colobot-lint, newer versions don't have llvm-3.6-dev in repo...
runs-on : ubuntu-16.04
env :
CC : /usr/lib/llvm-3.6/bin/clang
CXX : /usr/lib/llvm-3.6/bin/clang++
CLANG_PREFIX : /usr/lib/llvm-3.6
steps :
- name : Download Colobot dependencies
2020-07-09 17:35:25 +00:00
run : sudo apt-get update && sudo apt-get install -y --no-install-recommends build-essential cmake libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsndfile1-dev libvorbis-dev libogg-dev libpng-dev libglew-dev libopenal-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-regex-dev libphysfs-dev gettext git po4a vorbis-tools librsvg2-bin xmlstarlet
2020-07-07 12:19:21 +00:00
# TODO: migrate colobot-lint to GitHub Actions
- name : Download colobot-lint
run : |
sudo apt-get install -y --no-install-recommends clang-3.6 libtinyxml2.6.2v5
mkdir -p /tmp/colobot-lint
cd /tmp/colobot-lint
wget -O colobot-lint.zip "https://compiled.colobot.info/job/colobot/job/colobot-lint/job/dev/lastSuccessfulBuild/artifact/*zip*/archive.zip"
2020-07-09 16:55:40 +00:00
# Unzip the archive
unzip ./colobot-lint.zip
# Workaround for Clang not finding system headers
mkdir ./bin
mv ./archive/build/colobot-lint ./bin/
chmod +x ./bin/colobot-lint
ln -s ${CLANG_PREFIX}/lib ./lib
# Unpack HtmlReport
tar -zxf ./archive/build/html_report.tar.gz
# Clean up
rm -r ./archive
2020-07-09 16:56:08 +00:00
- uses : actions/checkout@v2
2020-07-12 21:12:06 +00:00
- name : Checkout the Google Test submodule
run : git submodule update --init -- lib/googletest
2020-07-07 12:19:21 +00:00
- name : Create build directory
run : cmake -E make_directory build
- name : Run CMake
working-directory : build
run : cmake -DCOLOBOT_LINT_BUILD=1 -DTESTS=1 -DTOOLS=1 -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..
- name : Run linter
shell : bash
run : |
set -e +x
2020-07-09 16:55:40 +00:00
WORKSPACE="$GITHUB_WORKSPACE"
2020-07-07 12:19:21 +00:00
COLOBOT_DIR="$WORKSPACE"
COLOBOT_BUILD_DIR="$WORKSPACE/build"
COLOBOT_LINT_REPORT_FILE="$WORKSPACE/build/colobot_lint_report.xml"
2020-07-09 16:55:40 +00:00
cd "/tmp/colobot-lint"
2020-07-07 12:19:21 +00:00
find "$WORKSPACE" \( -wholename "$COLOBOT_DIR/src/*.cpp" \
-or -wholename "$COLOBOT_DIR/test/unit/*.cpp" \
-or -wholename "$COLOBOT_BUILD_DIR/fake_header_sources/src/*.cpp" \
-or -wholename "$COLOBOT_BUILD_DIR/fake_header_sources/test/unit/*.cpp" \) \
-exec ./bin/colobot-lint \
-verbose \
-output-format xml \
-output-file "$COLOBOT_LINT_REPORT_FILE" \
-p "$COLOBOT_BUILD_DIR" \
-project-local-include-path "$COLOBOT_DIR/src" -project-local-include-path "$COLOBOT_BUILD_DIR/src" \
-license-template-file "$COLOBOT_DIR/LICENSE-HEADER.txt" \
{} +
- name : Upload results (XML)
uses : actions/upload-artifact@v2
with :
name : XML results
path : build/colobot_lint_report.xml
- name : Generate HTML report
shell : bash
2020-07-09 16:55:40 +00:00
run : /tmp/colobot-lint/HtmlReport/generate.py --xml-report "build/colobot_lint_report.xml" --output-dir "build/html_report"
2020-07-07 12:19:21 +00:00
- name : Upload results (HTML)
uses : actions/upload-artifact@v2
with :
name : HTML results
path : build/html_report
2020-07-09 16:42:52 +00:00
- run : pip install requests
- name : Send linter results to GitHub
shell : python
env :
GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
2020-07-07 12:19:21 +00:00
run : |
2020-07-09 16:42:52 +00:00
import os
import sys
import requests
import xml.etree.ElementTree as ET
OVERALL_STABLE_RULES=[
"class naming" ,
"code block placement" ,
"compile error" ,
# "compile warning",
# "enum naming",
# "function naming",
"header file not self-contained" ,
# "implicit bool cast",
# "include style",
# "inconsistent declaration parameter name",
"license header" ,
# "naked delete",
# "naked new",
# "old style function",
"old-style null pointer" ,
# "possible forward declaration",
"undefined function" ,
# "uninitialized field",
# "uninitialized local variable",
# "unused forward declaration",
# "variable naming",
"whitespace" ,
]
STABLE_RULES_WITHOUT_CBOT=[
"class naming" ,
"code block placement" ,
"compile error" ,
"compile warning" ,
# "enum naming",
# "function naming",
"header file not self-contained" ,
# "implicit bool cast",
"include style" ,
"inconsistent declaration parameter name" ,
"license header" ,
"naked delete" ,
"naked new" ,
# "old style function",
"old-style null pointer" ,
# "possible forward declaration",
"undefined function" ,
"uninitialized field" ,
# "uninitialized local variable",
"unused forward declaration" ,
# "variable naming",
"whitespace" ,
]
# None of the available actions seem to do what I want, they all do stupid things like adding another check... let's just do it manually
# GitHub also doesn't seem to provide you with the check suite or check run ID, so we have to get it from the action ID via the API
s = requests.Session()
s.headers.update({
'Authorization' : 'token ' + os.environ['GITHUB_TOKEN'],
'Accept' : 'application/vnd.github.antiope-preview+json' # Annotations are still technically a preview feature of the API
})
action_run = s.get(os.environ['GITHUB_API_URL'] + "/repos/" + os.environ['GITHUB_REPOSITORY'] + "/actions/runs/" + os.environ['GITHUB_RUN_ID']).json()
check_suite = s.get(action_run['check_suite_url']).json()
check_suite_runs = s.get(check_suite['check_runs_url']).json()
check_run = check_suite_runs['check_runs'][0] # NOTE : This assumes that the 'lint' job is the first one in the workflow. You could find it by name if you really wanted.
def we_care_about(file_name, type) :
if 'CBot' in file_name :
return type in OVERALL_STABLE_RULES
else :
return type in STABLE_RULES_WITHOUT_CBOT
results = ET.parse('build/colobot_lint_report.xml')
annotations = []
for error in results.find('errors').findall('error') :
location = error.find('location')
file_name = os.path.relpath(location.get('file'), os.environ['GITHUB_WORKSPACE'])
line_num = int(location.get('line'))
type = error.get('id')
severity = error.get('severity')
msg = error.get('msg')
gh_severity = 'warning'
if severity == 'error' :
gh_severity = 'failure'
elif severity == 'information' :
gh_severity = 'notice'
if not we_care_about(file_name, type) :
# don't send the unstable rules to github at all as there are way too many of them and it would overload the API rate limit
continue
print('{}:{}: [{}] {}'.format(file_name, line_num, type, msg))
annotations.append({
'path' : file_name,
'start_line' : line_num,
'end_line' : line_num,
'annotation_level' : gh_severity,
'title' : type,
'message' : msg
})
summary = 'colobot-lint found {} issues'.format(len(annotations))
all_ok = len(annotations) == 0
# Annotations have to be sent in batches of 50
first = True
while first or len(annotations) > 0 :
first = False
to_send = annotations[:50]
annotations = annotations[50:]
data = {
'output' : {
'title' : summary,
'summary' : summary,
'annotations' : to_send
}
}
r = s.patch(check_run['url'], json=data)
r.raise_for_status()
sys.exit(0 if all_ok else 1)