From 9e502b24639a7b7051d7b873c21ee3e71ed87c6b Mon Sep 17 00:00:00 2001 From: "Maarten A. Breddels" Date: Mon, 9 Oct 2023 12:26:52 +0200 Subject: [PATCH] ci,test: add ci and an UI based test using solara --- .bumpversion.cfg | 18 ++++++ .github/workflows/test.yml | 127 +++++++++++++++++++++++++++++++++++++ release.md | 26 ++++++++ release.sh | 6 ++ setup.py | 5 ++ tests/ui/popout_test.py | 31 +++++++++ 6 files changed, 213 insertions(+) create mode 100644 .bumpversion.cfg create mode 100644 .github/workflows/test.yml create mode 100644 release.md create mode 100755 release.sh create mode 100644 tests/ui/popout_test.py diff --git a/.bumpversion.cfg b/.bumpversion.cfg new file mode 100644 index 0000000..b21a887 --- /dev/null +++ b/.bumpversion.cfg @@ -0,0 +1,18 @@ +[bumpversion] +current_version = 1.0.0 +commit = True +tag = True +parse = (?P\d+)(\.(?P\d+))(\.(?P\d+))((?P.)(?P\d+))? +serialize = + {major}.{minor}.{patch}{release}{build} + {major}.{minor}.{patch} + +[bumpversion:part:release] +optional_value = g +first_value = g +values = + a + b + g + +[bumpversion:file:ipypopout/_version.py] diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..32954ff --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,127 @@ +name: Test + +on: + push: + pull_request: + workflow_dispatch: + schedule: + # Run at 2:00 a.m. every weekday (Monday to Friday) + - cron: "0 2 * * 1-5" + +jobs: + build: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + + - name: Install Python + uses: actions/setup-python@v2 + with: + python-version: "3.x" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install twine wheel jupyter-packaging "jupyterlab<4" + + - name: Build + run: | + python setup.py sdist bdist_wheel + + - name: Upload builds + uses: actions/upload-artifact@v3 + with: + name: ipypopout-dist-${{ github.run_number }} + path: | + ./dist + + test: + needs: [build] + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + python-version: [3.6, 3.7, 3.8, 3.9, "3.10", "3.11"] + steps: + - uses: actions/checkout@v2 + + - uses: actions/download-artifact@v3 + with: + name: ipypopout-dist-${{ github.run_number }} + # because we only upload 1 file, it's not put in a subdirectory + path: dist + + - name: Install Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install + run: pip install dist/*.whl + + - name: Import + # do the import in a subdirectory, as after installation, files in de current directory are also imported + run: | + (mkdir test-install; cd test-install; python -c "from ipypopout import PopoutButton") + + ui-test: + needs: [build] + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + + - uses: actions/download-artifact@v3 + with: + name: ipypopout-dist-${{ github.run_number }} + + - name: Install Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Install ipypopout and test deps + run: | + wheel=(dist/*.whl) + pip install ${wheel}[test] "jupyter_server<2" + + - name: Install playwright browsers + run: playwright install chromium + + - name: Run ui-tests + env: + # do not run solara (yet) + SOLARA_TEST_RUNNERS: "jupyter_lab,jupyter_notebook,voila" + run: pytest tests/ui/ --video=retain-on-failure --solara-update-snapshots-ci -s + + - name: Upload Test artifacts + if: always() + uses: actions/upload-artifact@v2 + with: + name: ipypopout-test-results + path: test-results + + release: + if: startsWith(github.event.ref, 'refs/tags/v') + needs: [test] + runs-on: ubuntu-20.04 + steps: + - uses: actions/download-artifact@v3 + with: + name: ipypopout-dist-${{ github.run_number }} + + - name: Install Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install twine wheel + + - name: Publish the Python package + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} + run: twine upload --skip-existing dist/* + diff --git a/release.md b/release.md new file mode 100644 index 0000000..fdd533f --- /dev/null +++ b/release.md @@ -0,0 +1,26 @@ + +# Fully automated + + $ ./release.sh patch + + +## Making an alpha release + + + $ ./release.sh patch --new-version 1.0.0 + + +# semi automated +To make a new release +``` +# update ipypopout/__init__.py +$ git add -u && git commit -m 'Release v1.0.0' && git tag v1.0.0 && git push upstream master v1.0.0 +``` + + +If a problem happens, and you want to keep the history clean +``` +# do fix +$ git rebase -i HEAD~3 +$ git tag v1.0.0 -f && git push upstream master v1.0.0 -f +``` diff --git a/release.sh b/release.sh new file mode 100755 index 0000000..0f104ed --- /dev/null +++ b/release.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -e -o pipefail +# usage: ./release minor -n +version=$(bump2version --dry-run --list $* | grep new_version | sed -r s,"^.*=",,) +echo Version tag v$version +bumpversion $* --verbose && git push upstream master v$version diff --git a/setup.py b/setup.py index e6ecd49..40e8cdf 100644 --- a/setup.py +++ b/setup.py @@ -59,6 +59,11 @@ def get_data_files(target, src): 'ipyvuetify>=1.7.0,<2', 'voila>=0.2.10' ], + extras_require={ + "test": [ + "solara[pytest]", + ] + }, data_files=get_data_files(os.path.join(*share_voila_target), os.path.join(template[0])), cmdclass={ 'develop': DevelopCmd, diff --git a/tests/ui/popout_test.py b/tests/ui/popout_test.py new file mode 100644 index 0000000..c3c7472 --- /dev/null +++ b/tests/ui/popout_test.py @@ -0,0 +1,31 @@ +import playwright.sync_api +from IPython.display import display +import ipypopout +import queue + +def test_popout( + ipywidgets_runner, page_session: playwright.sync_api.Page, context_session: playwright.sync_api.BrowserContext,assert_solara_snapshot +): + def kernel_code(): + import ipyvuetify as v + import ipypopout + + container = v.Container( + children=[], + ) + + button = ipypopout.PopoutButton( + target=container, + ) + text = v.Html(tag="div", children=["Test ipypopout"]) + container.children = [button, text] + display(container) + + ipywidgets_runner(kernel_code) + with context_session.expect_page() as new_page_info: + page_session.locator("_vue=v-btn[icon]").click() + new_page = new_page_info.value + new_page.locator("text=Test ipypopout").wait_for() + # the button should not be on the page + new_page.locator("_vue=v-btn").wait_for(state="detached") + new_page.close()