diff --git a/.github/workflows/integration_delivery.yml b/.github/workflows/integration_delivery.yml new file mode 100644 index 0000000..83dc922 --- /dev/null +++ b/.github/workflows/integration_delivery.yml @@ -0,0 +1,213 @@ +name: CI/CD + +on: + push: + pull_request: + workflow_dispatch: + +env: + PYTHON_VERSION: '3.11' + +jobs: + dependencies: + name: Install Dependencies + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + name: Checkout + + - name: Save Cached Poetry + id: cached-poetry + uses: actions/cache@v4 + with: + path: | + ~/.cache + ~/.local + key: poetry-${{ hashFiles('poetry.lock') }} + + - uses: actions/setup-python@v5 + name: Setup Python + with: + python-version: ${{ env.PYTHON_VERSION }} + architecture: x64 + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + virtualenvs-create: true + + - name: Install dependencies + run: poetry install --extras=dev + + type-check: + name: Type Check + needs: + - dependencies + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + name: Checkout + + - uses: actions/setup-python@v5 + name: Setup Python + with: + python-version: ${{ env.PYTHON_VERSION }} + architecture: x64 + + - name: Load Cached Poetry + id: cached-poetry + uses: actions/cache/restore@v4 + with: + path: | + ~/.cache + ~/.local + key: poetry-${{ hashFiles('poetry.lock') }} + + - name: Type Check + run: poetry run poe typecheck + + lint: + name: Lint + needs: + - dependencies + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + name: Checkout + + - uses: actions/setup-python@v5 + name: Setup Python + with: + python-version: ${{ env.PYTHON_VERSION }} + architecture: x64 + + - name: Load Cached Poetry + id: cached-poetry + uses: actions/cache/restore@v4 + with: + path: | + ~/.cache + ~/.local + key: poetry-${{ hashFiles('poetry.lock') }} + + - name: Lint + run: poetry run poe lint + + build: + name: Build + needs: + - dependencies + runs-on: ubuntu-latest + outputs: + version: ${{ steps.extract_version.outputs.version }} + name: ${{ steps.extract_version.outputs.name }} + steps: + - uses: actions/checkout@v4 + name: Checkout + + - uses: actions/setup-python@v5 + name: Setup Python + with: + python-version: ${{ env.PYTHON_VERSION }} + architecture: x64 + + - name: Load Cached Poetry + id: cached-poetry + uses: actions/cache/restore@v4 + with: + path: | + ~/.cache + ~/.local + key: poetry-${{ hashFiles('poetry.lock') }} + + - name: Build + run: poetry build + + - name: Extract Version + id: extract_version + run: | + echo "version=$(poetry version --short)" >> "$GITHUB_OUTPUT" + echo "name=$(poetry version | cut -d' ' -f1)" >> "$GITHUB_OUTPUT" + + - name: Upload wheel + uses: actions/upload-artifact@v4 + with: + name: wheel + path: dist/*.whl + if-no-files-found: error + + - name: Upload binary + uses: actions/upload-artifact@v4 + with: + name: binary + path: dist/*.tar.gz + if-no-files-found: error + + pypi-publish: + name: Publish to PyPI + if: >- + github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + needs: + - type-check + - lint + - build + runs-on: ubuntu-latest + environment: + name: release + url: https://pypi.org/p/${{ needs.build.outputs.name }} + permissions: + id-token: write + steps: + - uses: actions/download-artifact@v4 + with: + name: wheel + path: dist + + - uses: actions/download-artifact@v4 + with: + name: binary + path: dist + + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: dist + verbose: true + + release: + name: Release + needs: + - type-check + - lint + - build + - pypi-publish + environment: + name: release + url: https://pypi.org/p/${{ needs.build.outputs.name }} + runs-on: ubuntu-latest + permissions: + contents: write + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + steps: + - name: Procure Wheel + uses: actions/download-artifact@v4 + with: + name: wheel + path: artifacts + + - name: Procure Binary + uses: actions/download-artifact@v4 + with: + name: binary + path: artifacts + + - name: Release + uses: softprops/action-gh-release@v1 + with: + files: artifacts/* + tag_name: v${{ needs.build.outputs.version }} + body: | + Release of version ${{ needs.build.outputs.version }} + PyPI package: https://pypi.org/project/${{ needs.build.outputs.name }}/${{ needs.build.outputs.version }} + prerelease: false + draft: false diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml deleted file mode 100644 index da26bee..0000000 --- a/.github/workflows/wheels.yml +++ /dev/null @@ -1,47 +0,0 @@ ---- -name: Build - -on: [push, pull_request] - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - build_wheels: - name: Build wheels on ${{ matrix.os }} - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Set up python - uses: actions/setup-python@v4 - with: - python-version: '3.11' - - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - virtualenvs-create: true - virtualenvs-in-project: true - installer-parallel: true - - - name: Load cached venv - id: cached-poetry-dependencies - uses: actions/cache@v3 - with: - path: .venv - key: - venv-${{ runner.os }}-${{ - steps.setup-python.outputs.python-version}}-${{ - hashFiles('**/poetry.lock') }} - - - name: Build - run: poetry build - - - name: Upload - uses: actions/upload-artifact@v3 - with: - path: ./dist/*.whl diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b2642e..ac22d58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## Version 0.6.1 + +- chore: GitHub workflow to publish pushes on `main` branch to PyPI +- chore: create GitHub release for main branch in GitHub workflows + ## Version 0.6.0 - refactor: `HeadlessWidget` is not a singleton anymore, config migrated to config diff --git a/headless_kivy_pi/__init__.py b/headless_kivy_pi/__init__.py index 61de737..1c3fb75 100644 --- a/headless_kivy_pi/__init__.py +++ b/headless_kivy_pi/__init__.py @@ -30,7 +30,6 @@ from kivy.graphics.vertex_instructions import Rectangle from kivy.properties import ObjectProperty from kivy.uix.widget import Widget -from typing_extensions import Any from headless_kivy_pi import config from headless_kivy_pi.constants import IS_TEST_ENVIRONMENT @@ -94,7 +93,7 @@ def __init__(self: HeadlessWidget, **kwargs: dict[str, object]) -> None: super().__init__(**kwargs) self.render_trigger = Clock.create_trigger( - lambda _: self.render_on_display(), + self.render_on_display, 1 / self.fps, interval=True, ) @@ -109,8 +108,8 @@ def clear(*_: object) -> None: def add_widget( self: HeadlessWidget, - *args: Any, # noqa: ANN401 - **kwargs: Any, # noqa: ANN401 + *args: object, + **kwargs: object, ) -> None: """Extend `Widget.add_widget` and handle `canvas`.""" canvas = self.canvas @@ -120,8 +119,8 @@ def add_widget( def remove_widget( self: HeadlessWidget, - *args: Any, # noqa: ANN401 - **kwargs: Any, # noqa: ANN401 + *args: object, + **kwargs: object, ) -> None: """Extend `Widget.remove_widget` and handle `canvas`.""" canvas = self.canvas diff --git a/headless_kivy_pi/config.py b/headless_kivy_pi/config.py index 12e966b..a9536ce 100644 --- a/headless_kivy_pi/config.py +++ b/headless_kivy_pi/config.py @@ -1,5 +1,5 @@ # pyright: reportMissingImports=false -"""Implement `setup_kivy`, it configures Kivy.""" +"""Implement `setup_headless_kivy`, it configures headless-kivy-pi.""" from __future__ import annotations import atexit diff --git a/headless_kivy_pi/fake.py b/headless_kivy_pi/fake.py index 1a52bb4..92caa1b 100644 --- a/headless_kivy_pi/fake.py +++ b/headless_kivy_pi/fake.py @@ -16,13 +16,15 @@ def __init__(self: Fake) -> None: """Fake constructor.""" super().__init__('') - def __getattr__(self: Fake, attr: str) -> Fake: + def __getattr__(self: Fake, attr: str) -> Fake | str: """Fake all attrs.""" logger.debug( - 'Accessing fake attribute of a `Fake` instance', + 'Accessing fake attribute of a `Fake` insta', extra={'attr': attr}, ) - return Fake() + if attr == '__file__': + return 'fake' + return self def __call__(self: Fake, *args: object, **kwargs: object) -> Fake: """Fake call.""" diff --git a/pyproject.toml b/pyproject.toml index 9f27852..860966c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "headless-kivy-pi" -version = "0.6.0" +version = "0.6.1" description = "Headless renderer for Kivy framework on Raspberry Pi" authors = ["Sassan Haradji "] license = "Apache-2.0"