Merge branch 'github-actions-lint' into develop

develop
lethosor 2020-06-30 00:48:35 -04:00
commit 6a712b8b28
8 changed files with 106 additions and 38 deletions

@ -82,34 +82,47 @@ jobs:
if: success() || failure() if: success() || failure()
run: | run: |
rm -rf "$DF_FOLDER" rm -rf "$DF_FOLDER"
lint: lint:
runs-on: ubuntu-18.04 runs-on: ubuntu-18.04
steps: steps:
- name: Install dependencies - name: Set up Python 3
uses: actions/setup-python@v2
with:
python-version: 3
- name: Set up Ruby 2.7
uses: actions/setup-ruby@v1
with:
ruby-version: 2.7
- name: Install Lua
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install \ sudo apt-get install lua5.3
lua5.3 \
ruby
- name: Clone DFHack - name: Clone DFHack
uses: actions/checkout@v1 uses: actions/checkout@v2
with: with:
submodules: true submodules: true
# don't need tags here
- name: Check whitespace - name: Check whitespace
run: | run: |
python travis/lint.py python travis/lint.py
- name: Check Authors.rst - name: Check Authors.rst
if: success() || failure()
run: | run: |
python travis/authors-rst.py python travis/authors-rst.py
- name: Check for missing documentation - name: Check for missing documentation
if: success() || failure()
run: | run: |
python travis/script-docs.py python travis/script-docs.py
- name: Check Lua syntax - name: Check Lua syntax
if: success() || failure()
run: | run: |
python travis/script-syntax.py --ext=lua --cmd="luac5.3 -p" python travis/script-syntax.py --ext=lua --cmd="luac5.3 -p" --github-actions
- name: Check Ruby syntax - name: Check Ruby syntax
if: success() || failure()
run: | run: |
python travis/script-syntax.py --ext=rb --cmd="ruby -c" python travis/script-syntax.py --ext=rb --cmd="ruby -c" --github-actions
check-pr: check-pr:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'

@ -1,3 +1,4 @@
#!/usr/bin/env python3
import argparse, os, sys, time import argparse, os, sys, time
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()

@ -1,3 +1,4 @@
#!/usr/bin/env python3
""" Overly-complicated script to check formatting/sorting in Authors.rst """ """ Overly-complicated script to check formatting/sorting in Authors.rst """
import re, sys import re, sys

@ -1,3 +1,4 @@
#!/usr/bin/env python3
import glob import glob
import sys import sys

@ -1,3 +1,4 @@
#!/usr/bin/env python3
import re, os, sys import re, os, sys
valid_extensions = ['c', 'cpp', 'h', 'hpp', 'mm', 'lua', 'rb', 'proto', valid_extensions = ['c', 'cpp', 'h', 'hpp', 'mm', 'lua', 'rb', 'proto',
@ -18,12 +19,49 @@ def valid_file(filename):
not len(list(filter(lambda path: path.replace('\\', '/') in filename.replace('\\', '/'), path_blacklist))) not len(list(filter(lambda path: path.replace('\\', '/') in filename.replace('\\', '/'), path_blacklist)))
success = True success = True
def error(msg): def error(msg=None):
global success global success
success = False success = False
sys.stderr.write(msg + '\n') if msg:
sys.stderr.write(msg + '\n')
class LinterError(Exception): pass def format_lines(lines, total):
if len(lines) == total - 1:
return 'entire file'
if not len(lines):
# should never happen
return 'nowhere'
if len(lines) == 1:
return 'line %i' % lines[0]
s = 'lines '
range_start = range_end = lines[0]
for i, line in enumerate(lines):
if line > range_end + 1:
if range_start == range_end:
s += ('%i, ' % range_end)
else:
s += ('%i-%i, ' % (range_start, range_end))
range_start = range_end = line
if i == len(lines) - 1:
s += ('%i' % line)
else:
range_end = line
if i == len(lines) - 1:
s += ('%i-%i, ' % (range_start, range_end))
return s.rstrip(' ').rstrip(',')
class LinterError(Exception):
def __init__(self, message, lines, total_lines):
self.message = message
self.lines = lines
self.total_lines = total_lines
def __str__(self):
return '%s: %s' % (self.message, format_lines(self.lines, self.total_lines))
def github_actions_workflow_command(self, filename):
first_line = self.lines[0] if self.lines else 1
return '::error file=%s,line=%i::%s' % (filename, first_line, self)
class Linter(object): class Linter(object):
ignore = False ignore = False
@ -33,36 +71,12 @@ class Linter(object):
if not self.check_line(line): if not self.check_line(line):
failures.append(i + 1) failures.append(i + 1)
if len(failures): if len(failures):
raise LinterError('%s: %s' % (self.msg, self.display_lines(failures, len(lines)))) raise LinterError(self.msg, failures, len(lines))
def fix(self, lines): def fix(self, lines):
for i in range(len(lines)): for i in range(len(lines)):
lines[i] = self.fix_line(lines[i]) lines[i] = self.fix_line(lines[i])
def display_lines(self, lines, total):
if len(lines) == total - 1:
return 'entire file'
if not len(lines):
# should never happen
return 'nowhere'
if len(lines) == 1:
return 'line %i' % lines[0]
s = 'lines '
range_start = range_end = lines[0]
for i, line in enumerate(lines):
if line > range_end + 1:
if range_start == range_end:
s += ('%i, ' % range_end)
else:
s += ('%i-%i, ' % (range_start, range_end))
range_start = range_end = line
if i == len(lines) - 1:
s += ('%i' % line)
else:
range_end = line
if i == len(lines) - 1:
s += ('%i-%i, ' % (range_start, range_end))
return s.rstrip(' ').rstrip(',')
class NewlineLinter(Linter): class NewlineLinter(Linter):
msg = 'Contains DOS-style newlines' msg = 'Contains DOS-style newlines'
@ -91,6 +105,7 @@ class TabLinter(Linter):
linters = [cls() for cls in Linter.__subclasses__() if not cls.ignore] linters = [cls() for cls in Linter.__subclasses__() if not cls.ignore]
def main(): def main():
is_github_actions = os.environ.get('GITHUB_ACTIONS')
root_path = os.path.abspath(sys.argv[1] if len(sys.argv) > 1 else '.') root_path = os.path.abspath(sys.argv[1] if len(sys.argv) > 1 else '.')
if not os.path.exists(root_path): if not os.path.exists(root_path):
print('Nonexistent path: %s' % root_path) print('Nonexistent path: %s' % root_path)
@ -112,13 +127,22 @@ def main():
try: try:
lines[i] = line.decode('utf-8') lines[i] = line.decode('utf-8')
except UnicodeDecodeError: except UnicodeDecodeError:
error('%s:%i: Invalid UTF-8 (other errors will be ignored)' % (rel_path, i + 1)) msg_params = (rel_path, i + 1, 'Invalid UTF-8 (other errors will be ignored)')
if is_github_actions:
error()
print('::error file=%s,line=%i::%s' % msg_params)
else:
error('%s:%i: %s' % msg_params)
lines[i] = '' lines[i] = ''
for linter in linters: for linter in linters:
try: try:
linter.check(lines) linter.check(lines)
except LinterError as e: except LinterError as e:
error('%s: %s' % (rel_path, e)) if is_github_actions:
error()
print(e.github_actions_workflow_command(rel_path))
else:
error('%s: %s' % (rel_path, e))
if fix: if fix:
linter.fix(lines) linter.fix(lines)
contents = '\n'.join(lines) contents = '\n'.join(lines)

@ -1,3 +1,4 @@
#!/usr/bin/env python3
import argparse import argparse
import enum import enum
import json import json

@ -1,3 +1,4 @@
#!/usr/bin/env python3
from __future__ import print_function from __future__ import print_function
from io import open from io import open
import os import os

@ -1,8 +1,26 @@
#!/usr/bin/env python3
import argparse import argparse
import os import os
import subprocess import subprocess
import sys import sys
def print_stderr(stderr, args):
if not args.github_actions:
sys.stderr.write(stderr + '\n')
return
for line in stderr.split('\n'):
parts = list(map(str.strip, line.split(':')))
# e.g. luac prints "luac:" in front of messages, so find the first part
# containing the actual filename
for i in range(len(parts) - 1):
if parts[i].endswith('.' + args.ext) and parts[i + 1].isdigit():
print('::error file=%s,line=%s::%s' % (parts[i], parts[i + 1], ':'.join(parts[i + 2:])))
break
print(line)
def main(args): def main(args):
root_path = os.path.abspath(args.path) root_path = os.path.abspath(args.path)
cmd = args.cmd.split(' ') cmd = args.cmd.split(' ')
@ -19,7 +37,13 @@ def main(args):
continue continue
full_path = os.path.join(cur, filename) full_path = os.path.join(cur, filename)
try: try:
subprocess.check_output(cmd + [full_path]) p = subprocess.Popen(cmd + [full_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
_, stderr = p.communicate()
stderr = stderr.decode('utf-8', errors='ignore')
if stderr:
print_stderr(stderr, args)
if p.returncode != 0:
err = True
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
err = True err = True
except IOError: except IOError:
@ -34,5 +58,7 @@ if __name__ == '__main__':
parser.add_argument('--path', default='.', help='Root directory') parser.add_argument('--path', default='.', help='Root directory')
parser.add_argument('--ext', help='Script extension', required=True) parser.add_argument('--ext', help='Script extension', required=True)
parser.add_argument('--cmd', help='Command', required=True) parser.add_argument('--cmd', help='Command', required=True)
parser.add_argument('--github-actions', action='store_true',
help='Enable GitHub Actions workflow command output')
args = parser.parse_args() args = parser.parse_args()
main(args) main(args)