Skip to content

Commit 9628550

Browse files
Merge pull request #4 from jaspersiebring/linter
Added automatic testing and publishing through Github Actions
2 parents ebcbf22 + 8150109 commit 9628550

File tree

11 files changed

+436
-76
lines changed

11 files changed

+436
-76
lines changed

.github/workflows/main.yml

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
name: Quality control and automated release
2+
on:
3+
pull_request: # Pull request events (default: open, synchronized, reopened) in any branch triggers the workflow.
4+
push:
5+
branches:
6+
- main # Pushes to main (i.e. after a merged PR)
7+
jobs:
8+
checks_and_release:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Check out repository code
12+
uses: actions/checkout@v3
13+
- name: Installing Poetry globally
14+
run: pipx install poetry
15+
- name: Installing Python
16+
id: setup-python
17+
uses: actions/setup-python@v4
18+
with:
19+
python-version: 3.8
20+
- uses: actions/cache@v3
21+
with:
22+
path: /home/runner/.cache/pypoetry/virtualenvs
23+
key: poetry-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
24+
restore-keys: |
25+
poetry-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
26+
poetry-${{ steps.setup-python.outputs.python-version }}-
27+
28+
- name: Install dependencies
29+
run: |
30+
sudo apt update
31+
sudo apt install -y \
32+
dpkg-dev \
33+
build-essential \
34+
freeglut3-dev \
35+
libgl1-mesa-dev \
36+
libglu1-mesa-dev \
37+
libgstreamer-plugins-base1.0-dev \
38+
libgtk-3-dev \
39+
libjpeg-dev \
40+
libnotify-dev \
41+
libpng-dev \
42+
libsdl2-dev \
43+
libsm-dev \
44+
libunwind-dev \
45+
libtiff-dev \
46+
libwebkit2gtk-4.0-dev \
47+
libxtst-dev \
48+
libgtk2.0-dev
49+
50+
- name: Installing Poetry environment
51+
run: poetry install
52+
- name: Running pytest
53+
id: pytest
54+
run: poetry run pytest -v
55+
- name: Running mypy
56+
id: mypy
57+
run: poetry run mypy libretro_finder/ config/ tests/
58+
- name: Running pylint
59+
id: pylint
60+
run: poetry run pylint libretro_finder/ config/ tests/ --fail-under=8
61+
- name: Checking code coverage
62+
id: coverage
63+
run: poetry run pytest --cov=config --cov=libretro_finder --cov-fail-under=75
64+
65+
- name: Build source and .whl archives with Poetry
66+
id: build
67+
run: poetry build
68+
if: steps.pytest.outcome == 'success' && steps.mypy.outcome == 'success' && steps.pylint.outcome == 'success' && steps.coverage.outcome == 'success'
69+
- name: Authorize GitHub Actions to publish on PYPI
70+
run: poetry config pypi-token.pypi ${{ secrets.PYPI_API_TOKEN }}
71+
if: steps.build.outcome == 'success' && github.event_name == 'push'
72+
- name: Publish on PYPI
73+
run: poetry publish
74+
if: steps.build.outcome == 'success' && github.event_name == 'push'

.github/workflows/test_release.yml

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
name: Build and release on TestPyPi
2+
on:
3+
workflow_dispatch: # Manual trigger (dev)
4+
jobs:
5+
checks_and_release:
6+
runs-on: ubuntu-latest
7+
steps:
8+
- name: Check out repository code
9+
uses: actions/checkout@v3
10+
- name: Installing Poetry globally
11+
run: pipx install poetry
12+
- name: Installing Python
13+
id: setup-python
14+
uses: actions/setup-python@v4
15+
with:
16+
python-version: 3.8
17+
- uses: actions/cache@v3
18+
with:
19+
path: /home/runner/.cache/pypoetry/virtualenvs
20+
key: poetry-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
21+
restore-keys: |
22+
poetry-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
23+
poetry-${{ steps.setup-python.outputs.python-version }}-
24+
25+
- name: Install dependencies
26+
run: |
27+
sudo apt update
28+
sudo apt install -y \
29+
dpkg-dev \
30+
build-essential \
31+
freeglut3-dev \
32+
libgl1-mesa-dev \
33+
libglu1-mesa-dev \
34+
libgstreamer-plugins-base1.0-dev \
35+
libgtk-3-dev \
36+
libjpeg-dev \
37+
libnotify-dev \
38+
libpng-dev \
39+
libsdl2-dev \
40+
libsm-dev \
41+
libunwind-dev \
42+
libtiff-dev \
43+
libwebkit2gtk-4.0-dev \
44+
libxtst-dev \
45+
libgtk2.0-dev
46+
47+
- name: Installing Poetry environment
48+
run: poetry install
49+
- name: Running pytest
50+
id: pytest
51+
run: poetry run pytest -v
52+
- name: Running mypy
53+
id: mypy
54+
run: poetry run mypy libretro_finder/ config/ tests/
55+
- name: Running pylint
56+
id: pylint
57+
run: poetry run pylint libretro_finder/ config/ tests/ --fail-under=8
58+
- name: Checking code coverage
59+
id: coverage
60+
run: poetry run pytest --cov=config --cov=libretro_finder --cov-fail-under=75
61+
62+
- name: Build source and .whl archives with Poetry
63+
id: build
64+
run: poetry build
65+
if: steps.pytest.outcome == 'success' && steps.mypy.outcome == 'success' && steps.pylint.outcome == 'success' && steps.coverage.outcome == 'success'
66+
67+
- name: Authorize GitHub Actions to publish on PYPI
68+
run: |
69+
poetry config repositories.test-pypi https://test.pypi.org/legacy/
70+
poetry config pypi-token.test-pypi ${{ secrets.TESTPYPI_API_TOKEN }}
71+
if: steps.build.outcome == 'success'
72+
- name: Publish on PYPI
73+
run: poetry publish -r test-pypi
74+
if: steps.build.outcome == 'success'

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
[![PyPI](https://img.shields.io/pypi/v/libretro-finder)](https://pypi.org/project/libretro-finder/)
33
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/libretro-finder)
44
![PyPI - License](https://img.shields.io/pypi/l/libretro-finder)
5+
[![Build passing (main)](https://github.com/jaspersiebring/libretro_finder/actions/workflows/main.yml/badge.svg?branch=main&event=push)](https://github.com/jaspersiebring/libretro_finder/actions/workflows/main.yml)
6+
57

68
Simple tool that finds and prepares your BIOS files for usage with Libretro (or its RetroArch frontend).
79

@@ -89,5 +91,5 @@ If `libretro_finder` is called without any additional arguments, LibretroFinder
8991

9092

9193
### Missing features? Have some feedback? Let me know!
92-
- [My Reddit account](https://www.reddit.com/user/qtieb/)
93-
- [My Github account](https://github.com/jaspersiebring)
94+
- [Open a Github issue](https://github.com/jaspersiebring)
95+
- [Message me on Reddit ](https://www.reddit.com/user/qtieb/)

config/__init__.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020

2121
# Parsing Libretro's system.dat and formatting as pandas dataframe
2222
index = 0 # pylint: disable=invalid-name
23-
SYSTEMS = []
23+
24+
system_series = []
2425
with open(FILE_PATH, "r", encoding="utf-8") as file:
2526
for line in file:
2627
line = line.strip()
@@ -31,27 +32,27 @@
3132
r"name (\S+)(?: size (\S+))?(?: crc (\S+))?(?: md5 (\S+))?(?: sha1 (\S+))?",
3233
line,
3334
)
34-
data = {
35-
"system": current_system,
36-
"name": match.group(1).replace('"', "").replace("'", ""),
37-
"size": match.group(2) if match.group(2) else None,
38-
"crc": match.group(3) if match.group(3) else None,
39-
"md5": match.group(4) if match.group(4) else None,
40-
"sha1": match.group(5) if match.group(5) else None,
41-
}
42-
SYSTEMS.append(pd.DataFrame(data, index=[index]))
43-
index += 1
35+
if match:
36+
data = {
37+
"system": current_system,
38+
"name": match.group(1).replace('"', "").replace("'", ""),
39+
"size": match.group(2) if match.group(2) else None,
40+
"crc": match.group(3) if match.group(3) else None,
41+
"md5": match.group(4) if match.group(4) else None,
42+
"sha1": match.group(5) if match.group(5) else None,
43+
}
44+
system_series.append(pd.DataFrame(data, index=[index]))
45+
index += 1
4446

4547
# join dfs and drop features without checksums
46-
SYSTEMS = pd.concat(SYSTEMS)
48+
SYSTEMS = pd.concat(system_series)
4749
SYSTEMS = SYSTEMS[~SYSTEMS["md5"].isnull()].reset_index(drop=True)
4850

4951
# path to retroarch/system (if found)
5052
RETROARCH_PATH = find_retroarch()
5153

52-
5354
# 'cli' if user passes arguments else 'start gui'
5455
# Needs to be present before the @Gooey decorator (https://github.com/chriskiehl/Gooey/issues/449)
5556
if len(sys.argv) >= 2:
56-
if not "--ignore-gooey" in sys.argv:
57+
if "--ignore-gooey" not in sys.argv:
5758
sys.argv.append("--ignore-gooey")

libretro_finder/main.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import shutil
22
import pathlib
3+
from typing import List, Optional
34
import numpy as np
4-
from gooey import Gooey, GooeyParser
5-
5+
from gooey import Gooey, GooeyParser # type: ignore
66
from config import SYSTEMS as system_df
77
from config import RETROARCH_PATH
8-
from typing import List, Optional
98
from libretro_finder.utils import match_arrays, recursive_hash
109

1110

@@ -17,7 +16,6 @@ def organize(search_dir: pathlib.Path, output_dir: pathlib.Path) -> None:
1716
1817
:param search_dir: starting location of recursive search
1918
:param output_dir: path to output directory (will be created if it doesn't exist)
20-
:return:
2119
"""
2220

2321
# Indexing files to be checked for matching MD5 checksums
@@ -100,7 +98,7 @@ def main(argv: Optional[List[str]] = None) -> None:
10098

10199
if not search_directory.exists():
102100
raise FileNotFoundError("Search directory does not exist..")
103-
elif not search_directory.is_dir():
101+
if not search_directory.is_dir():
104102
raise NotADirectoryError("Search directory needs to be a directory..")
105103

106104
organize(search_dir=search_directory, output_dir=output_directory)

libretro_finder/utils.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
import concurrent.futures
33
import hashlib
44
import pathlib
5-
from typing import Tuple, Optional, List, Union
6-
from tqdm import tqdm
7-
import numpy as np
8-
import vdf
5+
from typing import Tuple, Optional, List
96
import platform
107
from string import ascii_uppercase
8+
from tqdm import tqdm
9+
import numpy as np
10+
import vdf # type: ignore
11+
1112

1213
# not expecting BIOS files over 15mb
1314
MAX_BIOS_BYTES = 15728640
@@ -34,7 +35,7 @@ def recursive_hash(
3435
3536
:param directory: Starting directory for the glob pattern matching
3637
:param glob: The glob pattern to match files. Defaults to "*".
37-
:return: An array with the file_paths to selected files and an array with the corresponding MD5 hashes
38+
:return: array with file_paths to selected files and an array with corresponding MD5 hashes
3839
"""
3940

4041
file_paths = list(directory.rglob(pattern=glob))
@@ -65,8 +66,8 @@ def match_arrays(
6566
6667
:param array_a: The first array to compare.
6768
:param array_b: The second array to compare.
68-
:return: A tuple of three numpy arrays: unique matching values, indices of the matching values in
69-
array_a and indices of the matching values in array_b.
69+
:return: A tuple of three numpy arrays: unique matching values, indices of the matching values
70+
in array_a and indices of the matching values in array_b.
7071
"""
7172

7273
# expecting 1D arrays
@@ -123,10 +124,10 @@ def find_retroarch() -> Optional[pathlib.Path]:
123124

124125
env_vars = ["PROGRAMFILES(X86)", "PROGRAMFILES"]
125126
for env_var in env_vars:
126-
env_var = os.environ.get(env_var)
127-
if not env_var:
127+
env_value = os.environ.get(env_var)
128+
if not env_value:
128129
continue
129-
env_path = pathlib.Path(env_var)
130+
env_path = pathlib.Path(env_value)
130131

131132
if env_path.exists():
132133
paths_to_check.append(env_path)
@@ -166,7 +167,7 @@ def find_retroarch() -> Optional[pathlib.Path]:
166167

167168
# checking for retroarch/system (one level down)
168169
for path_to_check in paths_to_check:
169-
# glob is needed for inconsistent parent naming (e.g. RetroArch-Win32, RetroArch-Win64, retroarch)
170+
# glob is needed for inconsistent parent naming (e.g. RetroArch-Win32, retroarch)
170171
for path in path_to_check.glob(system_glob):
171172
return path
172173
return None

0 commit comments

Comments
 (0)