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

Migrate CI/CD from AppVeyor to GitHub Actions #85

Merged
merged 56 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
e17e25d
Added GH Actions workflow to replace AppVeyor script
clyde-johnston Jun 11, 2023
68163eb
Amended _unittest_slow_cli_pub_sub_anon test assertion
clyde-johnston Jun 12, 2023
98758e8
Set twine credentials for pypi.org
clyde-johnston Jun 12, 2023
14d3f87
Separated workflows into test and deploy; PR#85 changes
clyde-johnston Aug 10, 2023
1877327
Removed in-line comment to pass strict test
clyde-johnston Aug 10, 2023
a71041c
Recombined workflows and release filter
clyde-johnston Aug 10, 2023
3b9a492
Update VERSION
pavel-kirienko Aug 12, 2023
7841934
Removed pull_request trigger and changed concurrency rule
clyde-johnston Aug 13, 2023
18ed993
Update CONTRIBUTING.md
pavel-kirienko Aug 19, 2023
637dfdb
Change network address to host address
pavel-kirienko Aug 19, 2023
1d6a1f2
Fix unused expression
pavel-kirienko Aug 19, 2023
e65de2f
Disable unnecessary checks in PyLint (MyPy addresses them better)
pavel-kirienko Aug 19, 2023
0a4633b
tests.subprocess: use temp files instead of pipes; this should fix th…
pavel-kirienko Aug 19, 2023
0241e4a
Split the with statement for compatibility with py3.8
pavel-kirienko Aug 19, 2023
361d386
Fix access error
pavel-kirienko Aug 19, 2023
3749a2d
Simplify the Subprocess interface
pavel-kirienko Aug 19, 2023
1d0f3a1
Typing
pavel-kirienko Aug 19, 2023
b5264c2
Typing
pavel-kirienko Aug 19, 2023
0fa9138
Reduce the number of concurrent processes
pavel-kirienko Aug 20, 2023
d94f732
Recognise nox exit code in Windows jobs
clyde-johnston Aug 21, 2023
fd39c0b
Merge branch 'main' into cicd
pavel-kirienko Jan 12, 2024
cea201d
Remove npcap-0.96.exe because we use pre-configured runners now; upda…
pavel-kirienko Jan 12, 2024
e8557e4
Use Ubuntu 22.04
pavel-kirienko Jan 12, 2024
3aa42bf
Force colored output in CI
pavel-kirienko Jan 12, 2024
a6d2bc4
Update tests: remove the obsolete 'can_transmit' property; skip the l…
pavel-kirienko Jan 12, 2024
9ce8d58
Test Python 3.11 as well
pavel-kirienko Jan 12, 2024
f612dbd
Robustify the tests on Windows
pavel-kirienko Jan 12, 2024
133d782
Enable Python 3.11 in nox.py
pavel-kirienko Jan 12, 2024
ae2e2b3
Bump the dev dependencies
pavel-kirienko Jan 12, 2024
76c8d3b
Clean up: use UDP instead of serial for testing as it is easier to se…
pavel-kirienko Jan 12, 2024
33a420e
Monitor test: add invalid frame injection
pavel-kirienko Jan 12, 2024
0a3d903
Re-enable monitor tests on Windows
pavel-kirienko Jan 12, 2024
99ff65e
mypy
pavel-kirienko Jan 12, 2024
bb23b53
Downgrade pytest-asyncio because of https://github.com/pytest-dev/pyt…
pavel-kirienko Jan 12, 2024
15a8955
Fix the failing pub expression tests
pavel-kirienko Jan 12, 2024
469e623
Fix the expression tests
pavel-kirienko Jan 16, 2024
77be997
MyPy fix
pavel-kirienko Jan 16, 2024
4530339
Enhance monitor test
pavel-kirienko Jan 18, 2024
ce48e7a
Address issues and enhance logging in the monitor test
pavel-kirienko Jan 18, 2024
c57a81a
Add diagnostic snapshot compression to save time
pavel-kirienko Jan 18, 2024
782298c
Fix the version handling during initialization
pavel-kirienko Jan 18, 2024
912c751
Fix logging
pavel-kirienko Jan 18, 2024
2116757
Adjust the tests and typing
pavel-kirienko Jan 18, 2024
7ad9d50
Enlarge timeouts in the monitor test
pavel-kirienko Jan 18, 2024
8a980e1
CI: update logging
pavel-kirienko Jan 22, 2024
fc66248
Fix the Subprocess finalizer
pavel-kirienko Jan 22, 2024
2237db0
Enhance logging
pavel-kirienko Jan 22, 2024
8b31d9a
Add explicit timeouts for the monitor tests
pavel-kirienko Jan 22, 2024
4ec113f
Revert "Add explicit timeouts for the monitor tests"
pavel-kirienko Jan 22, 2024
7edab65
Avoid CPU starvation in the monitor test
pavel-kirienko Jan 22, 2024
6c5092e
Enhance nox
pavel-kirienko Jan 22, 2024
821ed9e
Robustify the monitor tests
pavel-kirienko Jan 23, 2024
fdd8dc2
Fix the monitor errors test on Windows and hide unhelpful warnings there
pavel-kirienko Jan 23, 2024
b8939e8
Relax the timeouts in the file server test and fix stderr checking in…
pavel-kirienko Jan 23, 2024
813bc0c
.uavcan -> .dsdl
pavel-kirienko Jan 24, 2024
3da3aea
Relax the timeouts in the register tests
pavel-kirienko Jan 24, 2024
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
95 changes: 0 additions & 95 deletions .appveyor.yml

This file was deleted.

102 changes: 102 additions & 0 deletions .github/workflows/test-and-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: 'Test and Release Yakut'
on: push

# Ensures that only one workflow is running at a time
concurrency:
group: ${{ github.workflow_sha }}
cancel-in-progress: true

jobs:
yakut-test:
name: Test Yakut
strategy:
fail-fast: false
matrix:
# The Windows NPcap runner is an ordinary Windows machine with the NPcap driver installed manually.
# We chose to do it this way because NPcap driver installation requires a reboot, which is difficult to
# automate. The NPcap driver is required for the Cyphal/UDP transport tests to work.
os: [ubuntu-22.04, windows-2019-npcap]
python: ['3.8', '3.9', '3.10', '3.11']
exclude: # We don't test Windows with old Python versions because it takes too much effort.
- os: windows-2019-npcap
python: 3.8
- os: windows-2019-npcap
python: 3.9
runs-on: ${{ matrix.os }}
steps:
- name: Check out
uses: actions/checkout@v3

- name: Install Python3
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}

- name: Log Python version
run: python --version

- name: Install dependencies
# language=bash
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
sudo apt-get --ignore-missing update || true
sudo apt-get install -y linux-*-extra-$(uname -r) ncat
sudo apt-get install -y libsdl2-2.0-0 # For PySDL2. On Windows/macOS the binaries are pulled from PyPI.
sudo apt-get install -y libasound2-dev # For RtMidi.
fi
git submodule update --init --recursive
python -m pip install --upgrade pip setuptools nox
shell: bash

- name: Run build and test
# language=bash
run: |
nox --non-interactive --session test --python ${{ matrix.python }}
nox --non-interactive --session lint
shell: bash
env:
FORCE_COLOR: 1

- name: Upload diagnostics
uses: actions/upload-artifact@v3
if: (success() || failure())
with:
# The matrix is shown for convenience but this is fragile because the values may not be string-convertible.
# Shall it break one day, feel free to remove the matrix from here.
# The job status is per matrix item, which is super convenient.
name: ${{github.job}}-#${{strategy.job-index}}-${{job.status}}-${{join(matrix.*, ',')}}
path: "**/*.log"
retention-days: 7

yakut-release:
name: Release Yakut
runs-on: ubuntu-latest
if: contains(github.event.head_commit.message, '#release') || contains(github.ref, '/main')
needs: yakut-test
steps:
- name: Check out
uses: actions/checkout@v3

- name: Create distribution wheel
# language=bash
run: |
git submodule update --init --recursive
python -m pip install --upgrade pip setuptools wheel twine
python setup.py sdist bdist_wheel

- name: Get release version
run: echo "yakut_version=$(cat yakut/VERSION)" >> $GITHUB_ENV

- name: Upload distribution
run: |
python -m twine upload dist/*
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN_YAKUT }}

- name: Push version tag
uses: mathieudutour/[email protected]
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
custom_tag: ${{ env.yakut_version }}
tag_prefix: ''
3 changes: 3 additions & 0 deletions .idea/dictionaries/pavel.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This document is intended for developers only.
## Testing

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

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

Positional arguments given to Nox are passed over to PyTest as-is,
which can be used to run tests selectively or bail at the first failure:

```bash
nox -s test -- -x yakut/param/formatter.py -k test_format_param
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PyTest options
```

#### Running tests/linters selectively from a virtual environment created by Nox

Running the full test suite using Nox takes too much time for interactive testing during development.
Expand Down
34 changes: 20 additions & 14 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
assert DEPS_DIR.is_dir(), "Invalid configuration"


PYTHONS = ["3.8", "3.9", "3.10"]
PYTHONS = ["3.8", "3.9", "3.10", "3.11"]


@nox.session(python=False)
Expand Down Expand Up @@ -50,9 +50,9 @@ def test(session):

# Now we can install dependencies for the full integration test suite.
session.install(
"pytest ~= 7.1",
"pytest-asyncio == 0.18",
"coverage ~= 6.3",
"pytest ~= 7.4",
"pytest-asyncio ~= 0.21.0",
"coverage ~= 7.4",
)

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

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

src_dirs = [(ROOT_DIR / t) for t in ["yakut", "tests"]]

# Run PyTest and make a code coverage report.
env = {
"PYTHONPATH": str(DEPS_DIR),
"PATH": os.pathsep.join([session.env["PATH"], str(DEPS_DIR)]),
}
# Positional arguments passed to Nox after "--" are forwarded to PyTest as-is.
session.run(
"pytest",
*map(str, src_dirs),
# Log format cannot be specified in setup.cfg https://github.com/pytest-dev/pytest/issues/3062
r"--log-file-format=%(asctime)s %(levelname)-3.3s %(name)s: %(message)s",
env=env,
*session.posargs,
env={
"PYTHONPATH": str(DEPS_DIR),
"PATH": os.pathsep.join([session.env["PATH"], str(DEPS_DIR)]),
},
)

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


@nox.session(reuse_venv=True)
def lint(session):
session.install("pylint == 2.13.*")
session.install("pylint ~= 3.0.3")
session.run("pylint", "yakut", "tests")

session.install("black == 22.*")
session.install("black ~= 23.12")
session.run("black", "--check", ".")
9 changes: 7 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,16 @@ testpaths = yakut tests
python_files = *.py
python_classes = _UnitTest
python_functions = _unittest_
log_level = DEBUG
log_level = INFO
log_cli_level = WARNING
log_cli = true
log_file = pytest.log
log_file_level = DEBUG
# Unraisable exceptions are filtered because PyTest yields false-positives coming from PyCyphal.
addopts = --doctest-modules -v -p no:unraisableexception
asyncio_mode = auto
filterwarnings =
ignore:.*SDL2.*:UserWarning

# ---------------------------------------- MYPY ----------------------------------------
[mypy]
Expand Down Expand Up @@ -187,7 +190,9 @@ disable=
eval-used,
unspecified-encoding,
not-callable,
unbalanced-tuple-unpacking
unbalanced-tuple-unpacking,
no-name-in-module,
isinstance-second-argument-not-valid-type,

[pylint.REPORTS]
output-format=colorized
Expand Down
2 changes: 1 addition & 1 deletion tests/cmd/accommodate.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def _unittest_accommodate_swarm(transport_factory: TransportFactory, compiled_ds
# We spawn a lot of processes here, which might strain the test system a little, so beware. I've tested it
# with 120 processes and it made my workstation (24 GB RAM ~4 GHz Core i7) struggle to the point of being
# unable to maintain sufficiently real-time operation for the test to pass. Hm.
used_node_ids = list(range(10))
used_node_ids = list(range(5))
pubs = [
Subprocess.cli(
f"--transport={transport_factory(idx).expression}",
Expand Down
Loading
Loading