Skip to content

Commit 9e9cd2f

Browse files
Migrate CI/CD from AppVeyor to GitHub Actions (#85)
- GitHub Actions workflow created to replace AppVeyor. - Key test-related dependencies upgraded. - Support for python 3.11 added. - Certain time-sensitive tests updated with relaxed timeouts. - Explicit specification of the minor version number of DSDL types removed. --------- Co-authored-by: Pavel Kirienko <pavel.kirienko@gmail.com>
1 parent 53b7e54 commit 9e9cd2f

35 files changed

+450
-407
lines changed

.appveyor.yml

Lines changed: 0 additions & 95 deletions
This file was deleted.
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
name: 'Test and Release Yakut'
2+
on: push
3+
4+
# Ensures that only one workflow is running at a time
5+
concurrency:
6+
group: ${{ github.workflow_sha }}
7+
cancel-in-progress: true
8+
9+
jobs:
10+
yakut-test:
11+
name: Test Yakut
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
# The Windows NPcap runner is an ordinary Windows machine with the NPcap driver installed manually.
16+
# We chose to do it this way because NPcap driver installation requires a reboot, which is difficult to
17+
# automate. The NPcap driver is required for the Cyphal/UDP transport tests to work.
18+
os: [ubuntu-22.04, windows-2019-npcap]
19+
python: ['3.8', '3.9', '3.10', '3.11']
20+
exclude: # We don't test Windows with old Python versions because it takes too much effort.
21+
- os: windows-2019-npcap
22+
python: 3.8
23+
- os: windows-2019-npcap
24+
python: 3.9
25+
runs-on: ${{ matrix.os }}
26+
steps:
27+
- name: Check out
28+
uses: actions/checkout@v3
29+
30+
- name: Install Python3
31+
uses: actions/setup-python@v4
32+
with:
33+
python-version: ${{ matrix.python }}
34+
35+
- name: Log Python version
36+
run: python --version
37+
38+
- name: Install dependencies
39+
# language=bash
40+
run: |
41+
if [ "$RUNNER_OS" == "Linux" ]; then
42+
sudo apt-get --ignore-missing update || true
43+
sudo apt-get install -y linux-*-extra-$(uname -r) ncat
44+
sudo apt-get install -y libsdl2-2.0-0 # For PySDL2. On Windows/macOS the binaries are pulled from PyPI.
45+
sudo apt-get install -y libasound2-dev # For RtMidi.
46+
fi
47+
git submodule update --init --recursive
48+
python -m pip install --upgrade pip setuptools nox
49+
shell: bash
50+
51+
- name: Run build and test
52+
# language=bash
53+
run: |
54+
nox --non-interactive --session test --python ${{ matrix.python }}
55+
nox --non-interactive --session lint
56+
shell: bash
57+
env:
58+
FORCE_COLOR: 1
59+
60+
- name: Upload diagnostics
61+
uses: actions/upload-artifact@v3
62+
if: (success() || failure())
63+
with:
64+
# The matrix is shown for convenience but this is fragile because the values may not be string-convertible.
65+
# Shall it break one day, feel free to remove the matrix from here.
66+
# The job status is per matrix item, which is super convenient.
67+
name: ${{github.job}}-#${{strategy.job-index}}-${{job.status}}-${{join(matrix.*, ',')}}
68+
path: "**/*.log"
69+
retention-days: 7
70+
71+
yakut-release:
72+
name: Release Yakut
73+
runs-on: ubuntu-latest
74+
if: contains(github.event.head_commit.message, '#release') || contains(github.ref, '/main')
75+
needs: yakut-test
76+
steps:
77+
- name: Check out
78+
uses: actions/checkout@v3
79+
80+
- name: Create distribution wheel
81+
# language=bash
82+
run: |
83+
git submodule update --init --recursive
84+
python -m pip install --upgrade pip setuptools wheel twine
85+
python setup.py sdist bdist_wheel
86+
87+
- name: Get release version
88+
run: echo "yakut_version=$(cat yakut/VERSION)" >> $GITHUB_ENV
89+
90+
- name: Upload distribution
91+
run: |
92+
python -m twine upload dist/*
93+
env:
94+
TWINE_USERNAME: __token__
95+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN_YAKUT }}
96+
97+
- name: Push version tag
98+
uses: mathieudutour/github-tag-action@v6.1
99+
with:
100+
github_token: ${{ secrets.GITHUB_TOKEN }}
101+
custom_tag: ${{ env.yakut_version }}
102+
tag_prefix: ''

.idea/dictionaries/pavel.xml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

CONTRIBUTING.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ This document is intended for developers only.
55
## Testing
66

77
Install dependencies into your current Python environment: `pip install .`
8-
Aside from that, you will need to install other dependencies listed in `.appveyor.yml`
8+
Aside from that, you will need to install other dependencies listed in the CI/CD workflow files
99
(e.g., [Ncat](https://nmap.org/ncat/); for Debian-based distros try `apt install ncat`).
1010

1111
Write unit tests as functions without arguments prefixed with ``_unittest_``;
@@ -37,6 +37,14 @@ If you want to start from scratch, use `clean`:
3737
nox -s clean
3838
```
3939

40+
Positional arguments given to Nox are passed over to PyTest as-is,
41+
which can be used to run tests selectively or bail at the first failure:
42+
43+
```bash
44+
nox -s test -- -x yakut/param/formatter.py -k test_format_param
45+
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PyTest options
46+
```
47+
4048
#### Running tests/linters selectively from a virtual environment created by Nox
4149

4250
Running the full test suite using Nox takes too much time for interactive testing during development.

noxfile.py

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
assert DEPS_DIR.is_dir(), "Invalid configuration"
1616

1717

18-
PYTHONS = ["3.8", "3.9", "3.10"]
18+
PYTHONS = ["3.8", "3.9", "3.10", "3.11"]
1919

2020

2121
@nox.session(python=False)
@@ -50,9 +50,9 @@ def test(session):
5050

5151
# Now we can install dependencies for the full integration test suite.
5252
session.install(
53-
"pytest ~= 7.1",
54-
"pytest-asyncio == 0.18",
55-
"coverage ~= 6.3",
53+
"pytest ~= 7.4",
54+
"pytest-asyncio ~= 0.21.0",
55+
"coverage ~= 7.4",
5656
)
5757

5858
# The test suite generates a lot of temporary files, so we change the working directory.
@@ -64,20 +64,26 @@ def test(session):
6464
if not (tmp_dir / fn).exists():
6565
(tmp_dir / fn).symlink_to(ROOT_DIR / fn)
6666

67-
# The directories to test may be overridden if needed when invoking Nox.
68-
src_dirs = [(ROOT_DIR / t) for t in (session.posargs or ["yakut", "tests"])]
67+
if sys.platform.startswith("linux"):
68+
# Enable packet capture for the Python executable. This is necessary for commands that rely on low-level
69+
# network packet capture, such as the Monitor when used with Cyphal/UDP.
70+
# We do it here because the sudo may ask the user for the password; doing that from the suite is inconvenient.
71+
session.run("sudo", "setcap", "cap_net_raw+eip", str(Path(session.bin, "python").resolve()), external=True)
72+
73+
src_dirs = [(ROOT_DIR / t) for t in ["yakut", "tests"]]
6974

7075
# Run PyTest and make a code coverage report.
71-
env = {
72-
"PYTHONPATH": str(DEPS_DIR),
73-
"PATH": os.pathsep.join([session.env["PATH"], str(DEPS_DIR)]),
74-
}
76+
# Positional arguments passed to Nox after "--" are forwarded to PyTest as-is.
7577
session.run(
7678
"pytest",
7779
*map(str, src_dirs),
7880
# Log format cannot be specified in setup.cfg https://github.com/pytest-dev/pytest/issues/3062
7981
r"--log-file-format=%(asctime)s %(levelname)-3.3s %(name)s: %(message)s",
80-
env=env,
82+
*session.posargs,
83+
env={
84+
"PYTHONPATH": str(DEPS_DIR),
85+
"PATH": os.pathsep.join([session.env["PATH"], str(DEPS_DIR)]),
86+
},
8187
)
8288

8389
# The coverage threshold is intentionally set low for interactive runs because when running locally
@@ -98,14 +104,14 @@ def test(session):
98104
# 1. It requires access to the code generated by the test suite.
99105
# 2. It has to be run separately per Python version we support.
100106
# If the interpreter is not CPython, this may need to be conditionally disabled.
101-
session.install("mypy == 0.991")
107+
session.install("mypy ~= 1.8")
102108
session.run("mypy", "--strict", *map(str, src_dirs))
103109

104110

105111
@nox.session(reuse_venv=True)
106112
def lint(session):
107-
session.install("pylint == 2.13.*")
113+
session.install("pylint ~= 3.0.3")
108114
session.run("pylint", "yakut", "tests")
109115

110-
session.install("black == 22.*")
116+
session.install("black ~= 23.12")
111117
session.run("black", "--check", ".")

setup.cfg

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,16 @@ testpaths = yakut tests
9393
python_files = *.py
9494
python_classes = _UnitTest
9595
python_functions = _unittest_
96-
log_level = DEBUG
96+
log_level = INFO
9797
log_cli_level = WARNING
9898
log_cli = true
9999
log_file = pytest.log
100+
log_file_level = DEBUG
100101
# Unraisable exceptions are filtered because PyTest yields false-positives coming from PyCyphal.
101102
addopts = --doctest-modules -v -p no:unraisableexception
102103
asyncio_mode = auto
104+
filterwarnings =
105+
ignore:.*SDL2.*:UserWarning
103106

104107
# ---------------------------------------- MYPY ----------------------------------------
105108
[mypy]
@@ -187,7 +190,9 @@ disable=
187190
eval-used,
188191
unspecified-encoding,
189192
not-callable,
190-
unbalanced-tuple-unpacking
193+
unbalanced-tuple-unpacking,
194+
no-name-in-module,
195+
isinstance-second-argument-not-valid-type,
191196

192197
[pylint.REPORTS]
193198
output-format=colorized

tests/cmd/accommodate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def _unittest_accommodate_swarm(transport_factory: TransportFactory, compiled_ds
1515
# We spawn a lot of processes here, which might strain the test system a little, so beware. I've tested it
1616
# with 120 processes and it made my workstation (24 GB RAM ~4 GHz Core i7) struggle to the point of being
1717
# unable to maintain sufficiently real-time operation for the test to pass. Hm.
18-
used_node_ids = list(range(10))
18+
used_node_ids = list(range(5))
1919
pubs = [
2020
Subprocess.cli(
2121
f"--transport={transport_factory(idx).expression}",

0 commit comments

Comments
 (0)