Skip to content

Address review feedback #817

Address review feedback

Address review feedback #817

Workflow file for this run

name: CI
on:
push:
pull_request: ~
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
contents: read
jobs:
prepare-base:
name: Prepare base dependencies
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: venv
key: >-
1-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('pyproject.toml', 'Cargo.toml', 'Cargo.lock', 'src/**') }}
- name: Install system dependencies
if: steps.cache-venv.outputs.cache-hit != 'true'
run: sudo apt-get update && sudo apt-get install -y libudev-dev
- name: Set up Rust
if: steps.cache-venv.outputs.cache-hit != 'true'
run: rustup default stable && rustup update stable
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
uv venv venv
. venv/bin/activate
uv pip install -U pip setuptools setuptools-rust prek
PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 uv pip install -e .[dev]
- name: Cache base Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: venv
key: ${{ steps.cache-venv.outputs.cache-primary-key }}
prek:
name: Run prek
runs-on: ubuntu-latest
needs: prepare-base
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Python 3.11
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
id: python
with:
python-version: "3.11"
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
fail-on-cache-miss: true
path: venv
key: >-
1-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('pyproject.toml', 'Cargo.toml', 'Cargo.lock', 'src/**') }}
- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y libudev-dev
- name: Restore prek environment from cache
id: cache-prek
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/prek
key: |
1-${{ runner.os }}-prek-${{ hashFiles('prek.toml') }}
- name: Install prek hooks
if: steps.cache-prek.outputs.cache-hit != 'true'
run: |
. venv/bin/activate
prek prepare-hooks
- name: Cache prek environment
if: steps.cache-prek.outputs.cache-hit != 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/prek
key: ${{ steps.cache-prek.outputs.cache-primary-key }}
- name: Lint and static analysis
env:
SKIP: no-commit-to-branch
run: |
. venv/bin/activate
prek run --show-diff-on-failure --color=always --all-files
build-ser2net:
name: Build ser2net
runs-on: ubuntu-latest
env:
SER2NET_VERSION: "4.6.7"
GENSIO_VERSION: "3.0.2"
steps:
- name: Restore cached ser2net binary
id: cache-ser2net
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ser2net
key: ser2net-${{ env.SER2NET_VERSION }}-gensio-${{ env.GENSIO_VERSION }}
- name: Install build dependencies
if: steps.cache-ser2net.outputs.cache-hit != 'true'
run: |
sudo apt-get update
sudo apt-get install -y gcc make autoconf automake libtool pkg-config libyaml-dev
- name: Build gensio
if: steps.cache-ser2net.outputs.cache-hit != 'true'
run: |
git clone --depth=1 -b v$GENSIO_VERSION https://github.com/cminyard/gensio.git /tmp/gensio
cd /tmp/gensio
autoreconf -i
./configure \
--prefix=/tmp/gensio-install \
--enable-static \
--disable-shared \
--with-all-gensios=no \
--with-net=yes \
--with-telnet=yes \
--with-serialdev=yes \
--with-pthreads=yes \
--without-openssl \
--without-swig \
--without-python \
--without-tcl \
--without-glib
make -j$(nproc)
mkdir -p /tmp/gensio-install/libexec/gensio/$GENSIO_VERSION
make install
- name: Build ser2net
if: steps.cache-ser2net.outputs.cache-hit != 'true'
run: |
git clone --depth=1 -b v$SER2NET_VERSION https://github.com/cminyard/ser2net.git /tmp/ser2net
cd /tmp/ser2net
autoreconf -i
LDFLAGS="-L/tmp/gensio-install/lib" \
CFLAGS="-I/tmp/gensio-install/include" \
CPPFLAGS="-I/tmp/gensio-install/include" \
LIBS="-lgensioosh -lpthread" \
./configure --prefix=/usr/local --with-pam=no
make -j$(nproc) LDFLAGS="-all-static -L/tmp/gensio-install/lib"
cp ser2net $GITHUB_WORKSPACE/ser2net
- name: Verify ser2net binary
if: steps.cache-ser2net.outputs.cache-hit != 'true'
run: |
file $GITHUB_WORKSPACE/ser2net
$GITHUB_WORKSPACE/ser2net -v
- name: Cache ser2net binary
if: steps.cache-ser2net.outputs.cache-hit != 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ser2net
key: ${{ steps.cache-ser2net.outputs.cache-primary-key }}
compile-esphome:
name: Compile ESPHome host daemon
runs-on: ubuntu-latest
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Restore cached ESPHome binary
id: cache-esphome
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: tests/esphome/.esphome/build/serialx-host-daemon/.pioenvs/serialx-host-daemon/program
key: >-
2-esphome-daemon-${{ hashFiles('tests/esphome/host_daemon.yaml', 'tests/esphome/external_components/**') }}
- name: Set up Python 3.13
if: steps.cache-esphome.outputs.cache-hit != 'true'
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.13"
- name: Compile ESPHome host daemon
if: steps.cache-esphome.outputs.cache-hit != 'true'
env:
PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION: python
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
uv venv esphome-venv
. esphome-venv/bin/activate
uv pip install 'esphome>=2026.3.2'
esphome compile tests/esphome/host_daemon.yaml
- name: Cache ESPHome binary
if: steps.cache-esphome.outputs.cache-hit != 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: tests/esphome/.esphome/build/serialx-host-daemon/.pioenvs/serialx-host-daemon/program
key: ${{ steps.cache-esphome.outputs.cache-primary-key }}
pytest:
runs-on: ubuntu-latest
needs: [prepare-base, compile-esphome, build-ser2net]
env:
TTY0TTY_COMMIT: "dac0a105bee6997ebb3a06441c7befe3164c9fd1"
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
name: Run tests Python ${{ matrix.python-version }} (Linux)
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
id: python
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
fail-on-cache-miss: true
path: venv
key: >-
1-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('pyproject.toml', 'Cargo.toml', 'Cargo.lock', 'src/**') }}
- name: Restore cached ESPHome binary
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: tests/esphome/.esphome/build/serialx-host-daemon/.pioenvs/serialx-host-daemon/program
key: >-
2-esphome-daemon-${{ hashFiles('tests/esphome/host_daemon.yaml', 'tests/esphome/external_components/**') }}
- name: Restore cached ser2net binary
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ser2net
key: ser2net-4.6.7-gensio-3.0.2
- name: Install ser2net
run: |
sudo install -m 755 ser2net /usr/local/bin/ser2net
ser2net -v
- name: Get kernel version
id: kernel
run: echo "version=$(uname -r)" >> "$GITHUB_OUTPUT"
- name: Restore cached tty0tty module
id: cache-tty0tty
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: tty0tty.ko
key: tty0tty-${{ env.TTY0TTY_COMMIT }}-${{ steps.kernel.outputs.version }}
- name: Build tty0tty
if: steps.cache-tty0tty.outputs.cache-hit != 'true'
run: |
sudo apt-get install -y linux-headers-$(uname -r)
git clone https://github.com/lcgamboa/tty0tty /tmp/tty0tty
git -C /tmp/tty0tty checkout $TTY0TTY_COMMIT
make -C /tmp/tty0tty/module
cp /tmp/tty0tty/module/tty0tty.ko tty0tty.ko
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y socat libudev-dev
- name: Load tty0tty kernel module
run: |
sudo insmod tty0tty.ko
sudo chmod 666 /dev/tnt0 /dev/tnt1
- name: Set up uv
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Register Python problem matcher
run: |
echo "::add-matcher::.github/workflows/matchers/python.json"
- name: Install Pytest Annotation plugin
run: |
. venv/bin/activate
uv pip install pytest-github-actions-annotate-failures
- name: Run pytest
run: |
. venv/bin/activate
uv pip install pytest-xdist pytest-cov
python -m serialx.tools.list_ports
pytest \
-n auto \
-qq \
--timeout=20 \
--durations=10 \
--cov=serialx \
-o console_output_style=count \
-p no:sugar \
--adapter-pair /dev/tnt0,/dev/tnt1,no-rts-cts,no-dtr-dsr,no-num-unwritten-bytes,no-reset-write-buffer,no-write-timeout,no-buffer-control \
tests
- name: Upload coverage artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: coverage-${{ matrix.python-version }}
include-hidden-files: true
path: .coverage
pytest-macos:
runs-on: macos-latest
name: Run tests Python 3.13 (macOS)
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Python
id: python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.13"
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: venv
key: >-
1-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('pyproject.toml', 'Cargo.toml', 'Cargo.lock', 'src/**') }}
- name: Restore cached Rust extension
id: cache-ext
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: serialx/_serialx_rust*
key: >-
1-${{ runner.os }}-rust-ext-${{ steps.python.outputs.python-version }}-${{ hashFiles('Cargo.toml', 'Cargo.lock', 'src/**') }}
- name: Set up Rust
if: steps.cache-ext.outputs.cache-hit != 'true'
run: rustup default stable && rustup update stable
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv venv
. venv/bin/activate
pip install -e .[dev] pytest-cov
- name: Rebuild Rust extension
if: steps.cache-venv.outputs.cache-hit == 'true' && steps.cache-ext.outputs.cache-hit != 'true'
run: |
. venv/bin/activate
python setup.py build_ext --inplace
- name: Cache base Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: venv
key: ${{ steps.cache-venv.outputs.cache-primary-key }}
- name: Cache Rust extension
if: steps.cache-ext.outputs.cache-hit != 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: serialx/_serialx_rust*
key: ${{ steps.cache-ext.outputs.cache-primary-key }}
- name: Run tests
run: |
. venv/bin/activate
python -m serialx.tools.list_ports
pytest --timeout=20 --cov=serialx tests
- name: Upload coverage artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: coverage-macos-latest
include-hidden-files: true
path: .coverage
pytest-windows:
runs-on: windows-latest
name: Run tests Python 3.13 (Windows)
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Install com0com and hub4com
shell: pwsh
working-directory: tests/data/windows
run: |
Import-Certificate -FilePath com0com.cer -CertStoreLocation Cert:\LocalMachine\Root
Import-Certificate -FilePath com0com.cer -CertStoreLocation Cert:\LocalMachine\TrustedPublisher
.\setup_com0com_W7_x64_signed.exe /S
Expand-Archive -Path hub4com.zip -DestinationPath .
- name: Configure com0com
shell: pwsh
working-directory: C:\Program Files (x86)\com0com
run: |
.\setupc.exe --wait 1 install PortName=-,EmuBR=yes,cts=rrts,dsr=rdtr,dcd=rdtr PortName=-,EmuBR=yes,cts=rrts,dsr=rdtr,dcd=rdtr
- name: Set up Python
id: python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.13"
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: venv
key: >-
1-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('pyproject.toml', 'Cargo.toml', 'Cargo.lock', 'src/**') }}
- name: Restore cached Rust extension
id: cache-ext
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: serialx/_serialx_rust*
key: >-
1-${{ runner.os }}-rust-ext-${{ steps.python.outputs.python-version }}-${{ hashFiles('Cargo.toml', 'Cargo.lock', 'src/**') }}
- name: Set up Rust
if: steps.cache-ext.outputs.cache-hit != 'true'
run: rustup default stable && rustup update stable
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv venv
venv\Scripts\activate
pip install -e .[dev] pytest-cov
- name: Rebuild Rust extension
if: steps.cache-venv.outputs.cache-hit == 'true' && steps.cache-ext.outputs.cache-hit != 'true'
run: |
venv\Scripts\activate
python setup.py build_ext --inplace
- name: Cache base Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: venv
key: ${{ steps.cache-venv.outputs.cache-primary-key }}
- name: Cache Rust extension
if: steps.cache-ext.outputs.cache-hit != 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: serialx/_serialx_rust*
key: ${{ steps.cache-ext.outputs.cache-primary-key }}
- name: Run tests
shell: pwsh
run: |
venv\Scripts\activate
python -m serialx.tools.list_ports
pytest --timeout=20 --cov=serialx tests --adapter-pair CNCA0,CNCB0,no-buffer-control,no-rts-dtr-readback
- name: Upload coverage artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: coverage-windows-latest
include-hidden-files: true
path: .coverage
pytest-serialx-compat:
runs-on: ubuntu-latest
needs: prepare-base
name: Run serialx-compat tests (Python 3.10)
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Python 3.10
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
id: python
with:
python-version: "3.10"
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
fail-on-cache-miss: true
path: venv
key: >-
1-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('pyproject.toml', 'Cargo.toml', 'Cargo.lock', 'src/**') }}
- name: Install serialx-compat and run tests
run: |
. venv/bin/activate
pip install -e serialx_compat[dev]
pytest -q serialx_compat/tests
pytest-pyodide:
runs-on: ubuntu-slim
name: Run tests Pyodide (Bun)
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.13
- name: Cache Pyodide package wheels
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: tests/data/pyodide/node_modules/pyodide
key: >-
1-${{ runner.os }}-pyodide-${{ hashFiles('tests/data/pyodide/package.json',
'tests/data/pyodide/bun.lock') }}
- name: Install Bun dependencies
run: bun install --cwd tests/data/pyodide --frozen-lockfile
- name: Run tests under Pyodide
run: bun tests/data/pyodide/run_tests.ts --cov=serialx --cov-report=
- name: Upload coverage artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: coverage-pyodide
include-hidden-files: true
path: .coverage
coverage:
name: Process test coverage
runs-on: ubuntu-latest
needs: [pytest, pytest-macos, pytest-windows, pytest-pyodide]
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Python 3.10
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
id: python
with:
python-version: "3.10"
check-latest: true
- name: Restore base Python virtual environment
id: cache-venv
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
fail-on-cache-miss: true
path: venv
key: >-
1-${{ runner.os }}-base-venv-${{ steps.python.outputs.python-version }}-${{ hashFiles('pyproject.toml', 'Cargo.toml', 'Cargo.lock', 'src/**') }}
- name: Download all coverage artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- name: Combine coverage results
run: |
. venv/bin/activate
pip install coverage
coverage combine coverage*/.coverage*
coverage report
coverage xml
- name: Upload coverage to Codecov
if: ${{ github.event.repository.fork == false }}
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false