Skip to content

Commit

Permalink
add some CI
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelveldt committed Aug 23, 2024
1 parent ff0f2ca commit 7934b91
Show file tree
Hide file tree
Showing 14 changed files with 203 additions and 65 deletions.
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: weekly
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: weekly
26 changes: 26 additions & 0 deletions .github/release-drafter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name-template: "$RESOLVED_VERSION"
tag-template: "$RESOLVED_VERSION"
change-template: "- #$NUMBER - $TITLE (@$AUTHOR)"
categories:
- title: "⚠ Breaking Changes"
labels:
- "breaking-change"
- title: "⬆️ Dependencies"
collapse-after: 1
labels:
- "dependencies"
- "ci"
template: |
## What’s Changed
$CHANGES
version-resolver:
major:
labels:
- "breaking-change"
- "refactor"
minor:
labels:
- "new-feature"
- "enhancement"
default: patch
12 changes: 12 additions & 0 deletions .github/workflows/auto_approve_dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Auto approve Dependabot PR's

on: pull_request_target

jobs:
auto-approve:
runs-on: ubuntu-latest
permissions:
pull-requests: write
if: github.actor == 'dependabot[bot]'
steps:
- uses: hmarr/auto-approve-action@v4
23 changes: 23 additions & 0 deletions .github/workflows/pr-labels.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
name: PR Labels

# yamllint disable-line rule:truthy
on:
pull_request:
types:
- synchronize
- labeled
- unlabeled
branches:
- main

jobs:
pr_labels:
name: Verify
runs-on: ubuntu-latest
steps:
- name: 🏷 Verify PR has a valid label
uses: ludeeus/[email protected]
with:
labels: >-
breaking-change, bugfix, refactor, new-feature, maintenance, ci, dependencies
45 changes: 45 additions & 0 deletions .github/workflows/publish-to-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Publish releases to PyPI

on:
release:
types: [published, prereleased]

jobs:
build-and-publish-pypi:
name: Builds and publishes releases to PyPI
runs-on: ubuntu-latest
outputs:
version: ${{ steps.vars.outputs.tag }}
steps:
- uses: actions/checkout@v4
- name: Get tag
id: vars
run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
- name: Set up Python 3.10
uses: actions/[email protected]
with:
python-version: "3.10"
- name: Install build
run: >-
pip install build tomli tomli-w
- name: Set Python project version from tag
shell: python
run: |-
import tomli
import tomli_w
with open("pyproject.toml", "rb") as f:
pyproject = tomli.load(f)
pyproject["project"]["version"] = "${{ steps.vars.outputs.tag }}"
with open("pyproject.toml", "wb") as f:
tomli_w.dump(pyproject, f)
- name: Build
run: >-
python3 -m build
- name: Publish release to PyPI
uses: pypa/[email protected]
with:
user: __token__
password: ${{ secrets.PYPI_TOKEN }}
15 changes: 15 additions & 0 deletions .github/workflows/release-drafter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Release Drafter

on:
push:
branches:
- main

jobs:
update_release_draft:
runs-on: ubuntu-latest
steps:
# Drafts your next Release notes as Pull Requests are merged into "master"
- uses: release-drafter/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29 changes: 29 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# This workflow will install Python dependencies, run tests and lint
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: Test with Pre-commit

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
lint:
runs-on: ubuntu-latest
continue-on-error: true

steps:
- name: Check out code from GitHub
uses: actions/checkout@v4
- name: Set up Python
uses: actions/[email protected]
with:
python-version: "3.11"
- name: Install dependencies
run: |
python -m pip install --upgrade pip build setuptools
pip install . .[test]
- name: Lint/test with pre-commit
run: pre-commit run --all-files
20 changes: 8 additions & 12 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,21 +80,17 @@ repos:
always_run: true
args:
- --branch=main
- id: pylint
name: 🌟 Starring code with pylint
language: system
types: [python]
entry: scripts/run-in-env.sh pylint
- id: trailing-whitespace
name: ✄ Trim Trailing Whitespace
language: system
types: [text]
entry: scripts/run-in-env.sh trailing-whitespace-fixer
stages: [commit, push, manual]
- id: mypy
name: mypy
entry: scripts/run-in-env.sh mypy
language: script
types: [python]
require_serial: true
files: ^(music_assistant|pylint)/.+\.py$
# TODO: enable mypy (ans solve the issues found)
# - id: mypy
# name: mypy
# entry: scripts/run-in-env.sh mypy
# language: script
# types: [python]
# require_serial: true
# files: ^(aiosonos|pylint)/.+\.py$
5 changes: 4 additions & 1 deletion aiosonos/api/namespaces/playback_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

from __future__ import annotations

from collections.abc import Container
from typing import TYPE_CHECKING

from aiosonos.api.models import SessionStatus, Track

from ._base import SonosNameSpace, SubscribeCallbackType, UnsubscribeCallbackType

if TYPE_CHECKING:
from collections.abc import Container


class PlaybackSessionNameSpace(SonosNameSpace):
"""PlaybackSession Namespace handlers."""
Expand Down
16 changes: 11 additions & 5 deletions aiosonos/api/websockets.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ async def disconnect(self) -> None:
self._ws_client = None

def _handle_incoming_message(
self, raw: tuple[ResultMessage, dict[str, Any]]
self,
raw: tuple[ResultMessage, dict[str, Any]],
) -> None:
"""
Handle incoming message.
Expand All @@ -191,7 +192,7 @@ def _handle_incoming_message(
return
if future := self._result_futures.get(msg["cmdId"]):
future.set_exception(
FailedCommand(msg_data["errorCode"], msg_data.get("reason"))
FailedCommand(msg_data["errorCode"], msg_data.get("reason")),
)
return

Expand Down Expand Up @@ -255,13 +256,16 @@ async def receive_message_or_raise(self) -> tuple[ResultMessage, dict[str, Any]]

if self.logger.isEnabledFor(LOG_LEVEL_VERBOSE):
self.logger.log(
LOG_LEVEL_VERBOSE, "Received message:\n%s\n", pprint.pformat(ws_msg)
LOG_LEVEL_VERBOSE,
"Received message:\n%s\n",
pprint.pformat(ws_msg),
)

return msg

async def _send_message(
self, message: tuple[CommandMessage, dict[str, Any]]
self,
message: tuple[CommandMessage, dict[str, Any]],
) -> None:
"""
Send a message to the server.
Expand All @@ -273,7 +277,9 @@ async def _send_message(

if self.logger.isEnabledFor(LOG_LEVEL_VERBOSE):
self.logger.log(
LOG_LEVEL_VERBOSE, "Publishing message:\n%s\n", pprint.pformat(message)
LOG_LEVEL_VERBOSE,
"Publishing message:\n%s\n",
pprint.pformat(message),
)

assert self._ws_client
Expand Down
20 changes: 10 additions & 10 deletions aiosonos/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def subscribe(
Returns function to remove the listener.
Paramaters:
Parameters:
- cb_func: callback function or coroutine
- event_filter: Optionally only listen for these events
- object_id_filter: Optionally only listen for these id's (player id, etc.)
Expand Down Expand Up @@ -123,7 +123,8 @@ async def connect(self) -> None:
self._household_id = discovery_info["householdId"]
# Connect to the local websocket API
self.api = SonosLocalWebSocketsApi(
discovery_info["websocketUrl"], self._aiohttp_session
discovery_info["websocketUrl"],
self._aiohttp_session,
)
# NOTE: connect will raise when connecting failed
await self.api.connect()
Expand All @@ -137,7 +138,8 @@ async def start_listening(self, init_ready: asyncio.Event | None = None) -> None
listen_task = asyncio.create_task(self.api.start_listening())
# fetch all initial data and setup subscriptions
groups_data = await self.api.groups.get_groups(
self.household_id, include_device_info=True
self.household_id,
include_device_info=True,
)
for group_data in groups_data["groups"]:
await self._setup_group(group_data)
Expand All @@ -146,9 +148,7 @@ async def start_listening(self, init_ready: asyncio.Event | None = None) -> None
# so we ignore all other player objects. For each Sonos player,
# an individual api connection should be set-up to manage the player.
# The Cloud API however is able to manage all players in the household.
player_data = next(
x for x in groups_data["players"] if x["id"] == self._player_id
)
player_data = next(x for x in groups_data["players"] if x["id"] == self._player_id)
self._player = player = SonosPlayer(self, player_data)
await player.async_init()
# setup global groups/player subscription
Expand Down Expand Up @@ -178,7 +178,9 @@ async def create_group(
the new group will not contain any audio.
"""
await self.api.groups.create_group(
self._household_id, player_ids, music_context_group_id
self._household_id,
player_ids,
music_context_group_id,
)

def _handle_groups_event(self, groups_data: GroupsData) -> None:
Expand All @@ -192,9 +194,7 @@ def _handle_groups_event(self, groups_data: GroupsData) -> None:
# a new group was added
self._loop.create_task(self._setup_group(group_data))
# check if any groups are removed
removed_groups = set(self._groups.keys()) - {
g["id"] for g in groups_data["groups"]
}
removed_groups = set(self._groups.keys()) - {g["id"] for g in groups_data["groups"]}
for group_id in removed_groups:
group = self._groups.pop(group_id)
self.signal_event(
Expand Down
21 changes: 8 additions & 13 deletions aiosonos/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,12 @@

from typing import TYPE_CHECKING

from aiosonos.api.models import PlayBackState
from aiosonos.const import EventType, GroupEvent
from aiosonos.exceptions import FailedCommand

if TYPE_CHECKING:
from aiosonos.api.models import (
Container,
MetadataStatus,
PlayBackState,
SessionStatus,
Track,
)
from aiosonos.api.models import Container, MetadataStatus, SessionStatus, Track
from aiosonos.api.models import GroupVolume as GroupVolumeData
from aiosonos.api.models import PlaybackStatus as PlaybackStatusData
from aiosonos.api.models import PlayModes as PlayModesData
Expand Down Expand Up @@ -55,9 +50,7 @@ async def async_init(self) -> None:
# grab playback data and setup subscription
try:
self._volume_data = await self.client.api.group_volume.get_volume(self.id)
self._playback_status_data = (
await self.client.api.playback.get_playback_status(self.id)
)
self._playback_status_data = await self.client.api.playback.get_playback_status(self.id)
self._playback_actions = PlaybackActions(
self._playback_status_data["availablePlaybackActions"],
)
Expand All @@ -68,10 +61,12 @@ async def async_init(self) -> None:
)
)
await self.client.api.playback.subscribe(
self.id, self._handle_playback_status_update
self.id,
self._handle_playback_status_update,
)
await self.client.api.group_volume.subscribe(
self.id, self._handle_volume_update
self.id,
self._handle_volume_update,
)
await self.client.api.playback_metadata.subscribe(
self.id,
Expand Down Expand Up @@ -115,7 +110,7 @@ def playback_state(self) -> PlayBackState:

@property
def player_ids(self) -> list[str]:
"""Return ths id's of this group's members."""
"""Return the id's of this group's members."""
return self._data["playerIds"]

@property
Expand Down
Loading

0 comments on commit 7934b91

Please sign in to comment.