From 6bcb1b54cb4d06f34781d01aaba459b8b5e91154 Mon Sep 17 00:00:00 2001 From: George Melikov Date: Fri, 8 Aug 2025 18:18:21 +0300 Subject: [PATCH 1/2] Introduce CI Signed-off-by: George Melikov --- .github/workflows/publish-to-pypi.yml | 97 +++++++++++++++++++++++++++ .github/workflows/tests.yaml | 46 +++++++++++++ setup.cfg | 2 +- 3 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/publish-to-pypi.yml create mode 100644 .github/workflows/tests.yaml diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml new file mode 100644 index 0000000..182616f --- /dev/null +++ b/.github/workflows/publish-to-pypi.yml @@ -0,0 +1,97 @@ +name: Publish Python 🐍 distribution 📦 to PyPI + +on: + push: + tags: + - '*' + +jobs: + build: + name: Build distribution 📦 + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Install pypa/build + run: >- + python3 -m + pip install + build + --user + - name: Build a binary wheel and a source tarball + run: python3 -m build + - name: Store the distribution packages + uses: actions/upload-artifact@v4 + with: + name: python-package-distributions + path: dist/ + + publish-to-pypi: + name: >- + Publish Python 🐍 distribution 📦 to PyPI + needs: + - build + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/loopster + permissions: + id-token: write # IMPORTANT: mandatory for trusted publishing + + steps: + - name: Download all the dists + uses: actions/download-artifact@v4 + with: + name: python-package-distributions + path: dist/ + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + github-release: + name: >- + Sign the Python 🐍 distribution 📦 with Sigstore + and upload them to GitHub Release + needs: + - publish-to-pypi + runs-on: ubuntu-latest + + permissions: + contents: write # IMPORTANT: mandatory for making GitHub Releases + id-token: write # IMPORTANT: mandatory for sigstore + + steps: + - name: Download all the dists + uses: actions/download-artifact@v4 + with: + name: python-package-distributions + path: dist/ + - name: Sign the dists with Sigstore + uses: sigstore/gh-action-sigstore-python@v3.0.0 + with: + inputs: >- + ./dist/*.tar.gz + ./dist/*.whl + - name: Create GitHub Release + env: + GITHUB_TOKEN: ${{ github.token }} + run: >- + gh release create + "$GITHUB_REF_NAME" + --repo "$GITHUB_REPOSITORY" + --notes "" + - name: Upload artifact signatures to GitHub Release + env: + GITHUB_TOKEN: ${{ github.token }} + # Upload to GitHub Release using the `gh` CLI. + # `dist/` contains the built packages, and the + # sigstore-produced signatures and certificates. + run: >- + gh release upload + "$GITHUB_REF_NAME" dist/** + --repo "$GITHUB_REPOSITORY" diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 0000000..6d3e330 --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,46 @@ +name: tests + +on: + push: + pull_request: + +jobs: + Lint: + runs-on: ubuntu-24.04 + strategy: + fail-fast: true + matrix: + python-version: ["3.8"] + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install tox + run: pip install tox + - name: pep8 + run: | + tox -e pep8 + tests: + runs-on: ubuntu-24.04 + strategy: + fail-fast: true + matrix: + python-version: ["3.8", "3.10", "3.12", "3.13"] + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install required packages + run: | + sudo apt update + sudo apt install libev-dev -y + - name: Install tox + run: pip install tox + - name: Unit tests + run: | + tox -e ${{ matrix.python-version }} + - name: Functional tests + run: | + tox -e ${{ matrix.python-version }}-functional diff --git a/setup.cfg b/setup.cfg index 947bd74..a3759e7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,7 +6,7 @@ description-file = long_description_content_type = text/markdown author = VK Tech author-email = digital.tech@corp.mail.ru -home-page = http://infra.pages.gitlab.corp.mail.ru/iaas/libraries/rooster +home-page = https://github.com/vktechdev/loopster classifier = Intended Audience :: Developers License :: OSI Approved :: Apache Software License From 728cde30e3eb20d39d7cbc810920657eca843079 Mon Sep 17 00:00:00 2001 From: George Melikov Date: Fri, 8 Aug 2025 18:23:26 +0300 Subject: [PATCH 2/2] Fix pep8 to make CI green. Signed-off-by: George Melikov --- loopster/tests/unit/services/test_softirq.py | 78 +++++++++++++------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/loopster/tests/unit/services/test_softirq.py b/loopster/tests/unit/services/test_softirq.py index 8f987e5..baf30c4 100644 --- a/loopster/tests/unit/services/test_softirq.py +++ b/loopster/tests/unit/services/test_softirq.py @@ -47,9 +47,12 @@ def _step(self): class SoftIRQLoopStepMinorWatchdogErrorInTryTestCase(unittest.TestCase): - @mock.patch('loopster.services.softirq.SoftIrqService._send_wd_error_event') - @mock.patch('loopster.services.softirq.SoftIrqService._send_exc_step_event') - @mock.patch('loopster.services.softirq.SoftIrqService._send_step_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_wd_error_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_exc_step_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_step_event') @mock.patch('loopster.watchdogs.base.WatchDogBase.__enter__') def test_error_only_enter(self, enter, send, err_send, wd_send): enter.side_effect = FAKE_WD_MINOR_EXCEPTION @@ -60,9 +63,12 @@ def test_error_only_enter(self, enter, send, err_send, wd_send): err_send.assert_not_called() wd_send.assert_called_once() - @mock.patch('loopster.services.softirq.SoftIrqService._send_wd_error_event') - @mock.patch('loopster.services.softirq.SoftIrqService._send_exc_step_event') - @mock.patch('loopster.services.softirq.SoftIrqService._send_step_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_wd_error_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_exc_step_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_step_event') @mock.patch('loopster.watchdogs.base.WatchDogBase.__exit__') def test_error_only_exit(self, exit, send, err_send, wd_send): exit.side_effect = FAKE_WD_MINOR_EXCEPTION @@ -73,9 +79,12 @@ def test_error_only_exit(self, exit, send, err_send, wd_send): err_send.assert_not_called() wd_send.assert_called_once() - @mock.patch('loopster.services.softirq.SoftIrqService._send_wd_error_event') - @mock.patch('loopster.services.softirq.SoftIrqService._send_exc_step_event') - @mock.patch('loopster.services.softirq.SoftIrqService._send_step_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_wd_error_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_exc_step_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_step_event') def test_error_only_step(self, send, err_send, wd_send): s = TestService() with mock.patch.object(s, @@ -87,9 +96,12 @@ def test_error_only_step(self, send, err_send, wd_send): err_send.assert_called_once() wd_send.assert_not_called() - @mock.patch('loopster.services.softirq.SoftIrqService._send_wd_error_event') - @mock.patch('loopster.services.softirq.SoftIrqService._send_exc_step_event') - @mock.patch('loopster.services.softirq.SoftIrqService._send_step_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_wd_error_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_exc_step_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_step_event') @mock.patch('loopster.watchdogs.base.WatchDogBase.__exit__') def test_error_exit_and_step(self, exit, send, err_send, wd_send): exit.side_effect = FAKE_WD_MINOR_EXCEPTION @@ -103,9 +115,12 @@ def test_error_exit_and_step(self, exit, send, err_send, wd_send): err_send.assert_called_once() wd_send.assert_called_once() - @mock.patch('loopster.services.softirq.SoftIrqService._send_wd_error_event') - @mock.patch('loopster.services.softirq.SoftIrqService._send_exc_step_event') - @mock.patch('loopster.services.softirq.SoftIrqService._send_step_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_wd_error_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_exc_step_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_step_event') @mock.patch('loopster.watchdogs.base.WatchDogBase.__enter__') def test_error_enter_and_step(self, enter, send, err_send, wd_send): enter.side_effect = FAKE_WD_MINOR_EXCEPTION @@ -119,9 +134,12 @@ def test_error_enter_and_step(self, enter, send, err_send, wd_send): err_send.assert_not_called() wd_send.assert_called_once() - @mock.patch('loopster.services.softirq.SoftIrqService._send_wd_error_event') - @mock.patch('loopster.services.softirq.SoftIrqService._send_exc_step_event') - @mock.patch('loopster.services.softirq.SoftIrqService._send_step_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_wd_error_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_exc_step_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_step_event') @mock.patch('loopster.watchdogs.base.WatchDogBase.__exit__') @mock.patch('loopster.watchdogs.base.WatchDogBase.__enter__') def test_error_all(self, enter, exit, send, err_send, wd_send): @@ -137,8 +155,10 @@ def test_error_all(self, enter, exit, send, err_send, wd_send): err_send.assert_not_called() wd_send.assert_called_once() - @mock.patch('loopster.services.softirq.SoftIrqService._serve_fake') - @mock.patch('loopster.services.softirq.SoftIrqService._serve_operational') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._serve_fake') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._serve_operational') def test_only_step_enabled(self, serve_operational, serve_fake): s = TestService() @@ -147,8 +167,10 @@ def test_only_step_enabled(self, serve_operational, serve_fake): serve_operational.assert_called_once() serve_fake.assert_not_called() - @mock.patch('loopster.services.softirq.SoftIrqService._serve_fake') - @mock.patch('loopster.services.softirq.SoftIrqService._serve_operational') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._serve_fake') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._serve_operational') def test_only_step_not_enabled(self, serve_operational, serve_fake): s = TestService(operate=False) @@ -157,10 +179,14 @@ def test_only_step_not_enabled(self, serve_operational, serve_fake): serve_operational.assert_not_called() serve_fake.assert_called_once() - @mock.patch('loopster.services.softirq.SoftIrqService._send_wd_error_event') - @mock.patch('loopster.services.softirq.SoftIrqService._send_exc_step_event') - @mock.patch('loopster.services.softirq.SoftIrqService._send_step_event') - @mock.patch('loopster.services.softirq.SoftIrqService._on_sighup') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_wd_error_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_exc_step_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._send_step_event') + @mock.patch('loopster.services.softirq.SoftIrqService' + '._on_sighup') def test_loop_step_error_only_step_and_signum(self, on_sighup, send, err_send, wd_send): s = TestService(signum=multiprocessing.Value("i", 0))