Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added automatic testing and publishing through Github Actions #4

Merged
merged 20 commits into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
12b2882
Linter, formatter and added docs.
jaspersiebring Aug 8, 2023
7697bbc
Added initial workflow files for Github Actions
jaspersiebring Aug 8, 2023
6e91b8f
Added build caching
jaspersiebring Aug 8, 2023
4fb791d
Dropped abatilo/actions-poetry@v2 for poetry install, now just pipx i…
jaspersiebring Aug 8, 2023
3b913e2
Dropped dependency path
jaspersiebring Aug 8, 2023
f244628
Revert dummy test and added conditional poetry build step
jaspersiebring Aug 8, 2023
f9744c8
Changed conditional
jaspersiebring Aug 8, 2023
771e21c
Added code coverage check, stage and dep
jaspersiebring Aug 8, 2023
917b881
Dropped dummy workflow and added workflow with alternative caching (p…
jaspersiebring Aug 8, 2023
13a4cc0
Added release workflow with PYPI auth
jaspersiebring Aug 9, 2023
0f8b116
Checking partial restore_key matching with dummy dep
jaspersiebring Aug 9, 2023
18453ab
Github Actions refactor (now QC is triggered by PR activity and publi…
jaspersiebring Aug 9, 2023
672f8b6
Added cov fail and step echoes (temp)
jaspersiebring Aug 9, 2023
9842f83
Added publication conditional (testpypi)
jaspersiebring Aug 9, 2023
b22d824
Bundled workflow files in main.yml (with conditional releases).
jaspersiebring Aug 9, 2023
0381b97
Pushes to main now trigger a release on PyPi. Also added a workflow f…
jaspersiebring Aug 9, 2023
a338603
Dropped pytest-checksdocs dep
jaspersiebring Aug 9, 2023
b24423e
Initial poetry cache
jaspersiebring Aug 9, 2023
353c6b2
Added Github Actions badge and pylint line limit (100)
jaspersiebring Aug 9, 2023
8150109
Merge branch 'main' into linter
jaspersiebring Aug 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Quality control and automated release
on:
pull_request: # Pull request events (default: open, synchronized, reopened) in any branch triggers the workflow.
push:
branches:
- main # Pushes to main (i.e. after a merged PR)
jobs:
checks_and_release:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Installing Poetry globally
run: pipx install poetry
- name: Installing Python
id: setup-python
uses: actions/setup-python@v4
with:
python-version: 3.8
- uses: actions/cache@v3
with:
path: /home/runner/.cache/pypoetry/virtualenvs
key: poetry-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
restore-keys: |
poetry-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
poetry-${{ steps.setup-python.outputs.python-version }}-

- name: Install dependencies
run: |
sudo apt update
sudo apt install -y \
dpkg-dev \
build-essential \
freeglut3-dev \
libgl1-mesa-dev \
libglu1-mesa-dev \
libgstreamer-plugins-base1.0-dev \
libgtk-3-dev \
libjpeg-dev \
libnotify-dev \
libpng-dev \
libsdl2-dev \
libsm-dev \
libunwind-dev \
libtiff-dev \
libwebkit2gtk-4.0-dev \
libxtst-dev \
libgtk2.0-dev

- name: Installing Poetry environment
run: poetry install
- name: Running pytest
id: pytest
run: poetry run pytest -v
- name: Running mypy
id: mypy
run: poetry run mypy libretro_finder/ config/ tests/
- name: Running pylint
id: pylint
run: poetry run pylint libretro_finder/ config/ tests/ --fail-under=8
- name: Checking code coverage
id: coverage
run: poetry run pytest --cov=config --cov=libretro_finder --cov-fail-under=75

- name: Build source and .whl archives with Poetry
id: build
run: poetry build
if: steps.pytest.outcome == 'success' && steps.mypy.outcome == 'success' && steps.pylint.outcome == 'success' && steps.coverage.outcome == 'success'
- name: Authorize GitHub Actions to publish on PYPI
run: poetry config pypi-token.pypi ${{ secrets.PYPI_API_TOKEN }}
if: steps.build.outcome == 'success' && github.event_name == 'push'
- name: Publish on PYPI
run: poetry publish
if: steps.build.outcome == 'success' && github.event_name == 'push'
74 changes: 74 additions & 0 deletions .github/workflows/test_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Build and release on TestPyPi
on:
workflow_dispatch: # Manual trigger (dev)
jobs:
checks_and_release:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Installing Poetry globally
run: pipx install poetry
- name: Installing Python
id: setup-python
uses: actions/setup-python@v4
with:
python-version: 3.8
- uses: actions/cache@v3
with:
path: /home/runner/.cache/pypoetry/virtualenvs
key: poetry-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
restore-keys: |
poetry-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
poetry-${{ steps.setup-python.outputs.python-version }}-

- name: Install dependencies
run: |
sudo apt update
sudo apt install -y \
dpkg-dev \
build-essential \
freeglut3-dev \
libgl1-mesa-dev \
libglu1-mesa-dev \
libgstreamer-plugins-base1.0-dev \
libgtk-3-dev \
libjpeg-dev \
libnotify-dev \
libpng-dev \
libsdl2-dev \
libsm-dev \
libunwind-dev \
libtiff-dev \
libwebkit2gtk-4.0-dev \
libxtst-dev \
libgtk2.0-dev

- name: Installing Poetry environment
run: poetry install
- name: Running pytest
id: pytest
run: poetry run pytest -v
- name: Running mypy
id: mypy
run: poetry run mypy libretro_finder/ config/ tests/
- name: Running pylint
id: pylint
run: poetry run pylint libretro_finder/ config/ tests/ --fail-under=8
- name: Checking code coverage
id: coverage
run: poetry run pytest --cov=config --cov=libretro_finder --cov-fail-under=75

- name: Build source and .whl archives with Poetry
id: build
run: poetry build
if: steps.pytest.outcome == 'success' && steps.mypy.outcome == 'success' && steps.pylint.outcome == 'success' && steps.coverage.outcome == 'success'

- name: Authorize GitHub Actions to publish on PYPI
run: |
poetry config repositories.test-pypi https://test.pypi.org/legacy/
poetry config pypi-token.test-pypi ${{ secrets.TESTPYPI_API_TOKEN }}
if: steps.build.outcome == 'success'
- name: Publish on PYPI
run: poetry publish -r test-pypi
if: steps.build.outcome == 'success'
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
[![PyPI](https://img.shields.io/pypi/v/libretro-finder)](https://pypi.org/project/libretro-finder/)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/libretro-finder)
![PyPI - License](https://img.shields.io/pypi/l/libretro-finder)
[![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)


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

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


### Missing features? Have some feedback? Let me know!
- [My Reddit account](https://www.reddit.com/user/qtieb/)
- [My Github account](https://github.com/jaspersiebring)
- [Open a Github issue](https://github.com/jaspersiebring)
- [Message me on Reddit ](https://www.reddit.com/user/qtieb/)
29 changes: 15 additions & 14 deletions config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@

# Parsing Libretro's system.dat and formatting as pandas dataframe
index = 0 # pylint: disable=invalid-name
SYSTEMS = []

system_series = []
with open(FILE_PATH, "r", encoding="utf-8") as file:
for line in file:
line = line.strip()
Expand All @@ -31,27 +32,27 @@
r"name (\S+)(?: size (\S+))?(?: crc (\S+))?(?: md5 (\S+))?(?: sha1 (\S+))?",
line,
)
data = {
"system": current_system,
"name": match.group(1).replace('"', "").replace("'", ""),
"size": match.group(2) if match.group(2) else None,
"crc": match.group(3) if match.group(3) else None,
"md5": match.group(4) if match.group(4) else None,
"sha1": match.group(5) if match.group(5) else None,
}
SYSTEMS.append(pd.DataFrame(data, index=[index]))
index += 1
if match:
data = {
"system": current_system,
"name": match.group(1).replace('"', "").replace("'", ""),
"size": match.group(2) if match.group(2) else None,
"crc": match.group(3) if match.group(3) else None,
"md5": match.group(4) if match.group(4) else None,
"sha1": match.group(5) if match.group(5) else None,
}
system_series.append(pd.DataFrame(data, index=[index]))
index += 1

# join dfs and drop features without checksums
SYSTEMS = pd.concat(SYSTEMS)
SYSTEMS = pd.concat(system_series)
SYSTEMS = SYSTEMS[~SYSTEMS["md5"].isnull()].reset_index(drop=True)

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


# 'cli' if user passes arguments else 'start gui'
# Needs to be present before the @Gooey decorator (https://github.com/chriskiehl/Gooey/issues/449)
if len(sys.argv) >= 2:
if not "--ignore-gooey" in sys.argv:
if "--ignore-gooey" not in sys.argv:
sys.argv.append("--ignore-gooey")
8 changes: 3 additions & 5 deletions libretro_finder/main.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import shutil
import pathlib
from typing import List, Optional
import numpy as np
from gooey import Gooey, GooeyParser

from gooey import Gooey, GooeyParser # type: ignore
from config import SYSTEMS as system_df
from config import RETROARCH_PATH
from typing import List, Optional
from libretro_finder.utils import match_arrays, recursive_hash


Expand All @@ -17,7 +16,6 @@ def organize(search_dir: pathlib.Path, output_dir: pathlib.Path) -> None:

:param search_dir: starting location of recursive search
:param output_dir: path to output directory (will be created if it doesn't exist)
:return:
"""

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

if not search_directory.exists():
raise FileNotFoundError("Search directory does not exist..")
elif not search_directory.is_dir():
if not search_directory.is_dir():
raise NotADirectoryError("Search directory needs to be a directory..")

organize(search_dir=search_directory, output_dir=output_directory)
Expand Down
23 changes: 12 additions & 11 deletions libretro_finder/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
import concurrent.futures
import hashlib
import pathlib
from typing import Tuple, Optional, List, Union
from tqdm import tqdm
import numpy as np
import vdf
from typing import Tuple, Optional, List
import platform
from string import ascii_uppercase
from tqdm import tqdm
import numpy as np
import vdf # type: ignore


# not expecting BIOS files over 15mb
MAX_BIOS_BYTES = 15728640
Expand All @@ -34,7 +35,7 @@ def recursive_hash(

:param directory: Starting directory for the glob pattern matching
:param glob: The glob pattern to match files. Defaults to "*".
:return: An array with the file_paths to selected files and an array with the corresponding MD5 hashes
:return: array with file_paths to selected files and an array with corresponding MD5 hashes
"""

file_paths = list(directory.rglob(pattern=glob))
Expand Down Expand Up @@ -65,8 +66,8 @@ def match_arrays(

:param array_a: The first array to compare.
:param array_b: The second array to compare.
:return: A tuple of three numpy arrays: unique matching values, indices of the matching values in
array_a and indices of the matching values in array_b.
:return: A tuple of three numpy arrays: unique matching values, indices of the matching values
in array_a and indices of the matching values in array_b.
"""

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

env_vars = ["PROGRAMFILES(X86)", "PROGRAMFILES"]
for env_var in env_vars:
env_var = os.environ.get(env_var)
if not env_var:
env_value = os.environ.get(env_var)
if not env_value:
continue
env_path = pathlib.Path(env_var)
env_path = pathlib.Path(env_value)

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

# checking for retroarch/system (one level down)
for path_to_check in paths_to_check:
# glob is needed for inconsistent parent naming (e.g. RetroArch-Win32, RetroArch-Win64, retroarch)
# glob is needed for inconsistent parent naming (e.g. RetroArch-Win32, retroarch)
for path in path_to_check.glob(system_glob):
return path
return None
Loading