Add github actions workflows (#267)

* Run linters and unit tests with github actions

* Reformat with black, 22.1.0 (compiled: yes)

* Remove native deps as should no longer be needed

* Remove pylint from workflows

* Remove unused Gtk dependency in test_daemon.py

* Install subset of python deps with apt-get for ci
pull/298/head
Luna Nova 2 years ago committed by GitHub
parent 162e7fcbf7
commit ee6b48ac32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,25 @@
name: Lint
on: [push, pull_request]
jobs:
black:
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
strategy:
matrix:
python-version: ["3.10"]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
scripts/ci-install-deps.sh
pip install black
- name: Analysing the code with black --check --diff
run: |
black --check --diff ./inputremapper ./tests

@ -0,0 +1,46 @@
---
name: reviewdog
# run reviewdog for PR only because "github-check" option is failing :(
# https://github.com/reviewdog/reviewdog/issues/924
on: [pull_request]
jobs:
reviewdog_python:
name: reviewdog - Python lint
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10"]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- uses: reviewdog/action-setup@master
with:
reviewdog_version: latest
- name: Install dependencies
shell: bash
run: |
scripts/ci-install-deps.sh
pip install flake8 pylint mypy black
- name: Set env for PR
if: github.event_name == 'pull_request'
shell: bash
run: echo "REWIEVDOG_REPORTER=github-pr-review" >> $GITHUB_ENV
- name: Set env for push
if: github.event_name != 'pull_request'
shell: bash
run: echo "REWIEVDOG_REPORTER=github-check" >> $GITHUB_ENV
- name: Run reviewdog
shell: bash
env:
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
reviewdog -list
reviewdog -tee -runners=mypy,black -reporter=${{ env.REWIEVDOG_REPORTER }} -fail-on-error=false

@ -0,0 +1,28 @@
name: Test
on: [push, pull_request]
jobs:
build:
continue-on-error: true
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
strategy:
matrix:
python-version: ["3.7", "3.10"] # min and max supported versions?
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
# Install deps as root since we will run tests as root
sudo scripts/ci-install-deps.sh
sudo pip install .
- name: Run tests
run: |
# FIXME: Had some permissions issues, currently worked around by running tests as root
mkdir test_tmp
TMPDIR="$(realpath test_tmp)" sudo python tests/test.py --start-dir unit

@ -0,0 +1,21 @@
---
runner:
mypy:
name: mypy
cmd: mypy --show-column-numbers inputremapper tests --ignore-missing-imports
errorformat:
- "%f:%l:%c: %m"
pylint:
name: pylint
cmd: pylint inputremapper tests --extension-pkg-whitelist=evdev
errorformat:
- "%f:%l:%c: %t%n: %m"
flake8:
cmd: flake8 inputremapper tests
format: flake8
black:
cmd: black --diff --quiet --check ./inputremapper ./tests
format: black

@ -213,7 +213,7 @@ class JoystickToMouse(Consumer):
non_linearity = preset.get("gamepad.joystick.non_linearity") non_linearity = preset.get("gamepad.joystick.non_linearity")
x_scroll_speed = preset.get("gamepad.joystick.x_scroll_speed") x_scroll_speed = preset.get("gamepad.joystick.x_scroll_speed")
y_scroll_speed = preset.get("gamepad.joystick.y_scroll_speed") y_scroll_speed = preset.get("gamepad.joystick.y_scroll_speed")
max_speed = 2 ** 0.5 # for normalized abs event values max_speed = 2**0.5 # for normalized abs event values
if abs_range is not None: if abs_range is not None:
logger.info( logger.info(

@ -27,7 +27,9 @@ from typing import Tuple
from inputremapper.exceptions import InputEventCreationError from inputremapper.exceptions import InputEventCreationError
@dataclass(frozen=True) # Todo: add slots=True as soon as python 3.10 is in common distros @dataclass(
frozen=True
) # Todo: add slots=True as soon as python 3.10 is in common distros
class InputEvent: class InputEvent:
""" """
the evnet used by inputremapper the evnet used by inputremapper

@ -0,0 +1,14 @@
#!/usr/bin/env bash
# Called from multiple CI pipelines in .github/workflows
set -xeuo pipefail
# native deps
# gettext required to generate translations, others are python deps
sudo apt-get install -y gettext python3-evdev python3-pydbus python3-pydantic
# ensure pip and setuptools/wheel up to date so can install all pip modules
python -m pip install --upgrade pip
pip install wheel setuptools
# install test deps which aren't in setup.py
pip install psutil

@ -129,13 +129,7 @@ setup(
("/usr/bin/", ["bin/key-mapper-service"]), ("/usr/bin/", ["bin/key-mapper-service"]),
("/usr/bin/", ["bin/key-mapper-control"]), ("/usr/bin/", ["bin/key-mapper-control"]),
], ],
install_requires=[ install_requires=["setuptools", "evdev", "pydbus", "pygobject", "pydantic"],
"setuptools",
"evdev",
"pydbus",
"pygobject",
"pydantic"
],
cmdclass={ cmdclass={
"install": Install, "install": Install,
}, },

@ -0,0 +1,48 @@
# shell.nix - used with nix-shell to get a development environment with necessary dependencies
# Should be enough to run unit tests, integration tests and the service won't work
# If you don't use nix, don't worry about/use this file
let
pkgs = import <nixpkgs> { };
python = pkgs.python310;
in
pkgs.mkShell {
nativeBuildInputs = [
pkgs.pkg-config
pkgs.wrapGAppsHook
];
buildInputs = [
pkgs.gobject-introspection
pkgs.gtk3
pkgs.bashInteractive
pkgs.gobject-introspection
pkgs.xlibs.xmodmap
pkgs.gtksourceview4
(python.withPackages (
python-packages: with python-packages; [
pip
wheel
setuptools # for pkg_resources
types-setuptools
evdev
pydbus
pygobject3
pydantic
psutil # only used in tests
]
))
];
# https://nixos.wiki/wiki/Python#Emulating_virtualenv_with_nix-shell
shellHook = ''
# Tells pip to put packages into $PIP_PREFIX instead of the usual locations.
# See https://pip.pypa.io/en/stable/user_guide/#environment-variables.
export PIP_PREFIX=$(pwd)/venv
export PYTHONPATH="$PIP_PREFIX/${python.sitePackages}:$PYTHONPATH"
export PATH="$PIP_PREFIX/bin:$PATH"
unset SOURCE_DATE_EPOCH
python setup.py egg_info
pip install `grep -v '^\[' *.egg-info/requires.txt` || true
'';
}

@ -699,12 +699,18 @@ class TestGui(GuiTestBase):
def test_editor_keycode_to_string(self): def test_editor_keycode_to_string(self):
# not an integration test, but I have all the selection_label tests here already # not an integration test, but I have all the selection_label tests here already
self.assertEqual(EventCombination((EV_KEY, evdev.ecodes.KEY_A, 1)).beautify(), "a") self.assertEqual(
EventCombination((EV_KEY, evdev.ecodes.KEY_A, 1)).beautify(), "a"
)
self.assertEqual( self.assertEqual(
EventCombination([EV_KEY, evdev.ecodes.KEY_A, 1]).beautify(), "a" EventCombination([EV_KEY, evdev.ecodes.KEY_A, 1]).beautify(), "a"
) )
self.assertEqual(EventCombination((EV_ABS, evdev.ecodes.ABS_HAT0Y, -1)).beautify(), "DPad Up") self.assertEqual(
self.assertEqual(EventCombination((EV_KEY, evdev.ecodes.BTN_A, 1)).beautify(), "Button A") EventCombination((EV_ABS, evdev.ecodes.ABS_HAT0Y, -1)).beautify(), "DPad Up"
)
self.assertEqual(
EventCombination((EV_KEY, evdev.ecodes.BTN_A, 1)).beautify(), "Button A"
)
self.assertEqual(EventCombination((EV_KEY, 1234, 1)).beautify(), "1234") self.assertEqual(EventCombination((EV_KEY, 1234, 1)).beautify(), "1234")
self.assertEqual( self.assertEqual(
EventCombination([EV_ABS, evdev.ecodes.ABS_HAT0X, -1]).beautify(), EventCombination([EV_ABS, evdev.ecodes.ABS_HAT0X, -1]).beautify(),
@ -1736,7 +1742,7 @@ class TestGui(GuiTestBase):
gtk_iteration() gtk_iteration()
speed = active_preset.get("gamepad.joystick.pointer_speed") speed = active_preset.get("gamepad.joystick.pointer_speed")
active_preset.set("gamepad.joystick.non_linearity", 1) active_preset.set("gamepad.joystick.non_linearity", 1)
self.assertEqual(speed, 2 ** 6) self.assertEqual(speed, 2**6)
# don't consume the events in the reader, they are used to test # don't consume the events in the reader, they are used to test
# the injection # the injection

@ -20,6 +20,7 @@
"""Sets up inputremapper for the tests and runs them.""" """Sets up inputremapper for the tests and runs them."""
import argparse
import os import os
import sys import sys
import tempfile import tempfile
@ -663,7 +664,15 @@ cleanup()
def main(): def main():
modules = sys.argv[1:] # https://docs.python.org/3/library/argparse.html
parser = argparse.ArgumentParser(description=__doc__)
# repeated argument 0 or more times with modules
parser.add_argument("modules", type=str, nargs="*")
# start-dir value if not using modules, allows eg python tests/test.py --start-dir unit
parser.add_argument("--start-dir", type=str, default=".")
parsed_args = parser.parse_args() # takes from sys.argv by default
modules = parsed_args.modules
# discoverer is really convenient, but it can't find a specific test # discoverer is really convenient, but it can't find a specific test
# in all of the available tests like unittest.main() does..., # in all of the available tests like unittest.main() does...,
# so provide both options. # so provide both options.
@ -674,7 +683,9 @@ def main():
testsuite = unittest.defaultTestLoader.loadTestsFromNames(modules) testsuite = unittest.defaultTestLoader.loadTestsFromNames(modules)
else: else:
# run all tests by default # run all tests by default
testsuite = unittest.defaultTestLoader.discover(".", pattern="test_*.py") testsuite = unittest.defaultTestLoader.discover(
parsed_args.start_dir, pattern="test_*.py"
)
# add a newline to each "qux (foo.bar)..." output before each test, # add a newline to each "qux (foo.bar)..." output before each test,
# because the first log will be on the same line otherwise # because the first log will be on the same line otherwise

@ -27,7 +27,6 @@ import json
import evdev import evdev
from evdev.ecodes import EV_KEY, EV_ABS, KEY_B, KEY_A from evdev.ecodes import EV_KEY, EV_ABS, KEY_B, KEY_A
from gi.repository import Gtk
from pydbus import SystemBus from pydbus import SystemBus
from inputremapper.configs.system_mapping import system_mapping from inputremapper.configs.system_mapping import system_mapping
@ -51,12 +50,6 @@ from tests.test import (
) )
def gtk_iteration():
"""Iterate while events are pending."""
while Gtk.events_pending():
Gtk.main_iteration()
check_output = subprocess.check_output check_output = subprocess.check_output
os_system = os.system os_system = os.system
dbus_get = type(SystemBus()).get dbus_get = type(SystemBus()).get

@ -91,10 +91,14 @@ class TestInputEvent(unittest.TestCase):
) )
self.assertEqual(e1.type_and_code, (evdev.ecodes.EV_KEY, evdev.ecodes.BTN_LEFT)) self.assertEqual(e1.type_and_code, (evdev.ecodes.EV_KEY, evdev.ecodes.BTN_LEFT))
with self.assertRaises(FrozenInstanceError): # would be TypeError on a slotted class with self.assertRaises(
FrozenInstanceError
): # would be TypeError on a slotted class
e1.event_tuple = (1, 2, 3) e1.event_tuple = (1, 2, 3)
with self.assertRaises(FrozenInstanceError): # would be TypeError on a slotted class with self.assertRaises(
FrozenInstanceError
): # would be TypeError on a slotted class
e1.type_and_code = (1, 2) e1.type_and_code = (1, 2)
with self.assertRaises(FrozenInstanceError): with self.assertRaises(FrozenInstanceError):

Loading…
Cancel
Save