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

ci: perf #193

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
194 changes: 108 additions & 86 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,35 +48,112 @@ jobs:
with:
extra_args: --all-files --color=always

build-wheel:
name: Build python wheel
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
# update the version
- name: Get short commit SHA
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
SHA="${{ github.event.pull_request.head.sha }}"
else
SHA="${{ github.sha }}"
fi
echo "SHA=$(git rev-parse --short $SHA)" >> $GITHUB_ENV
- name: Get current version (MAJOR.MINOR.PATCH)
id: current-version
run: echo "current_version=$(grep -Po '(?<=__version__ = ")[\d\w.]+(?=")' rdmo/__init__.py)" >> $GITHUB_OUTPUT
- name: Generate new version (current version + SHA)
id: new-version
run: echo "new_version=${{ steps.current-version.outputs.current_version }}+$SHA" >> $GITHUB_OUTPUT
- name: Update version in rdmo/__init__.py
run: |
sed -i "s/__version__ = .*/__version__ = \"${{ steps.new-version.outputs.new_version }}\"/" rdmo/__init__.py
# build the webpack bundle
- uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
- run: npm install && npm run build:prod
# build the wheel
- uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: pip
- run: |
python -m pip install --upgrade pip pipx
pip --version
pipx --version
- name: Build the wheel
run: pipx run build
- name: Check the metadata
run: pipx run twine check --strict dist/*
- name: Install package from built wheel
run: python -m pip install --no-compile dist/rdmo*.whl # do not create __pycache__/*.pyc files
- name: Write info to step summary
run: |
{
echo -e "# ✓ Wheel successfully built (v${{ steps.new-version.outputs.new_version }})\n\n"
echo '<details><summary>Information about installed wheel</summary>'
echo -e "\n\`\`\`console"
echo "$ python -m pip show --files --verbose rdmo"
python -m pip show --files --verbose rdmo
echo -e "\`\`\`\n</details>"
} >> $GITHUB_STEP_SUMMARY
- name: Upload wheel as artifact
uses: actions/upload-artifact@v4
with:
name: wheel
path: dist/rdmo*.whl
if-no-files-found: error
retention-days: 30

test:
name: "Test (Python: ${{ matrix.python-version }}, DB: ${{ matrix.db-backend }})" # TODO: add end-to-end to name
needs: build-wheel
runs-on: ubuntu-24.04
timeout-minutes: 45
strategy:
matrix:
python-version: ['3.8', '3.12']
db-backend: [mysql, postgres]
name: "Test (Python: ${{ matrix.python-version }}, DB: ${{ matrix.db-backend }})"
needs: lint
end-to-end: [false]
include:
- python-version: '3.12'
db-backend: postgres
end-to-end: true
steps:
- run: echo "true"
if: matrix.end-to-end
- run: echo "false"
if: matrix.end-to-end == false
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
- name: Download wheel
uses: actions/download-artifact@v4
with:
name: wheel
path: dist
- name: Install Dependencies
run: |
sudo apt update
sudo apt install --yes pandoc texlive-xetex librsvg2-bin
python -m pip install --upgrade pip
sudo apt-get update && sudo apt-get install --yes pandoc texlive-xetex librsvg2-bin
pandoc --version
- name: Install rdmo[mysql] and start mysql
python -m pip install --upgrade pip
python -m pip --version
- name: Install rdmo[mysql] from wheel and start mysql
run: |
python -m pip install --editable .[ci,mysql]
python -m pip install "$(ls dist/*.whl)[ci,mysql]"
sudo systemctl start mysql.service
if: matrix.db-backend == 'mysql'
- name: Install rdmo[postgres] and start postgresql
- name: Install rdmo[postgres] from wheel and start postgresql
run: |
python -m pip install --editable .[ci,postgres]
python -m pip install "$(ls dist/*.whl)[ci,postgres]"
sudo systemctl start postgresql.service
pg_isready
sudo -u postgres psql --command="CREATE USER postgres_user PASSWORD 'postgres_password' CREATEDB"
Expand All @@ -89,41 +166,36 @@ jobs:
run: |
pytest rdmo/core/tests/test_package_status.py::test_package_json_and_pre_commit_versions_match \
--nomigrations --verbose
if: matrix.python-version == '3.12' && matrix.db-backend == 'postgres'
if: matrix.end-to-end
- name: Run Tests
run: |
pytest -p randomly -p no:cacheprovider --cov --reuse-db --numprocesses=auto --dist=loadscope
env:
GITHUB_DB_BACKEND: ${{ matrix.db-backend }}
if: matrix.end-to-end == false
- name: Upload coverage data to coveralls.io
uses: coverallsapp/github-action@643bc377ffa44ace6394b2b5d0d3950076de9f63 # v2.3.0
with:
flag-name: '${{ matrix.db-backend }}: ${{ matrix.python-version }}'
parallel: true
if: matrix.end-to-end == false
# end-to-end tests
- uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
if: matrix.python-version == '3.12' && matrix.db-backend == 'postgres'
- name: Install e2e tests dependencies
run: |
npm install
npm run build:prod
playwright install chromium
if: matrix.python-version == '3.12' && matrix.db-backend == 'postgres'
- run: mkdir screenshots
run: python -m playwright install --with-deps chromium
if: matrix.end-to-end
- name: Run end-to-end tests
run: pytest -p randomly -p no:cacheprovider --reuse-db --numprocesses=auto --dist=loadscope -m e2e --nomigrations
if: matrix.python-version == '3.12' && matrix.db-backend == 'postgres'
run: |
mkdir screenshots
pytest --nomigrations -m e2e
if: matrix.end-to-end
env:
DJANGO_DEBUG: True
GITHUB_DB_BACKEND: ${{ matrix.db-backend }}
- uses: actions/upload-artifact@v4
with:
name: screenshots
path: screenshots/*.png
if: matrix.python-version == '3.12' && matrix.db-backend == 'postgres'
if: matrix.end-to-end

coveralls:
name: Indicate completion to coveralls
Expand All @@ -136,63 +208,6 @@ jobs:
with:
parallel-finished: true

build-wheel:
name: Build python wheel
needs: test
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Get short commit SHA
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
SHA="${{ github.event.pull_request.head.sha }}"
else
SHA="${{ github.sha }}"
fi
echo "SHA=$(git rev-parse --short $SHA)" >> $GITHUB_ENV
- name: Get current version (MAJOR.MINOR.PATCH)
id: current-version
run: echo "current_version=$(grep -Po '(?<=__version__ = ")[\d\w.]+(?=")' rdmo/__init__.py)" >> $GITHUB_OUTPUT
- name: Generate new version (current version + SHA)
id: new-version
run: echo "new_version=${{ steps.current-version.outputs.current_version }}+$SHA" >> $GITHUB_OUTPUT
- name: Update version in rdmo/__init__.py
run: |
sed -i "s/__version__ = .*/__version__ = \"${{ steps.new-version.outputs.new_version }}\"/" rdmo/__init__.py
- uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
- run: npm install
- run: npm run build:prod
- uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: pip
- run: |
python -m pip install --upgrade pip
python -m pip install .[dev]
- name: Build the wheel
run: python -m build --wheel
- name: Check metadata
run: python -m twine check --strict dist/*
- name: Install package from built wheel
run: python -m pip install --force-reinstall dist/rdmo*.whl
- name: Write info to step summary
run: |
echo -e "# ✓ Wheel successfully built (v${{ steps.new-version.outputs.new_version }})\n\n" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`console" >> $GITHUB_STEP_SUMMARY
echo "$ python -m pip show rdmo" >> $GITHUB_STEP_SUMMARY
python -m pip show rdmo >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
- name: Upload wheel as artifact
uses: actions/upload-artifact@v4
with:
name: wheel
path: dist/rdmo*.whl
if-no-files-found: error
retention-days: 30

dev-setup:
# Ref: structlog (MIT licensed) <https://github.com/hynek/structlog/blob/main/.github/workflows/ci.yml>
name: "Test dev setup on ${{ matrix.os }}"
Expand All @@ -211,19 +226,26 @@ jobs:

dependencies:
name: Test installation of all dependencies
needs: build-wheel
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip
- name: Download wheel
uses: actions/download-artifact@v4
with:
name: wheel
path: dist
- name: Install os requirements for python-ldap
run: |
sudo apt update
sudo apt install --yes libldap2-dev libsasl2-dev
run: sudo apt-get update && sudo apt-get install --yes libldap2-dev libsasl2-dev
- run: python -m pip install --upgrade pip
- run: python -m pip install .[allauth,ci,dev,gunicorn,ldap,mysql,postgres,pytest]
- name: Install rdmo wheel with all optional dependency groups
run: python -m pip install --no-compile "$(ls dist/*.whl)[allauth,ci,dev,gunicorn,ldap,mysql,postgres,pytest]"
- name: Verify installed packages have compatible dependencies
run: python -m pip check
- uses: actions/setup-node@v4
with:
node-version: 18
Expand Down Expand Up @@ -259,9 +281,9 @@ jobs:
if: always()
needs:
- lint
- build-wheel
- test
- coveralls
- build-wheel
- dev-setup
- dependencies
runs-on: ubuntu-24.04
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ filterwarnings = [
"ignore:'cgi' is deprecated and slated for removal in Python 3.13:DeprecationWarning",
"ignore:pkg_resources is deprecated as an API:DeprecationWarning",

"ignore:CoreAPI compatibility is deprecated and will be removed in DRF 3.17:rest_framework.RemovedInDRF317Warning",

# ignore warnings raised from within django itself
# django/core/files/storage/__init__.py
"ignore:django.core.files.storage.get_storage_class is deprecated:django.utils.deprecation.RemovedInDjango51Warning",
Expand Down
66 changes: 47 additions & 19 deletions rdmo/management/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest

from django.core.management import call_command

from django.conf import settings
from playwright.sync_api import BrowserType, Page, expect
from pytest_django.live_server_helper import LiveServer

Expand All @@ -18,32 +18,60 @@ def _e2e_tests_django_db_setup(django_db_setup, django_db_blocker, fixtures):


@pytest.fixture
def base_url_page(live_server: LiveServer, browser: BrowserType) -> Page:
def base_url_page(
django_user_model,
username,
live_server: LiveServer,
browser: BrowserType) -> Page:
"""Enable playwright to address URLs with base URL automatically prefixed."""
context = browser.new_context(base_url=live_server.url)
page = context.new_page()
# context = browser.new_context(base_url=live_server.url)
user = django_user_model.objects.get(username=username)
print(user)
page = browser.new_page()
yield page
context.close()
# context.close()


# helper function for logging in the user
def login_user(page: Page, username: str, password: str) -> Page:
page.goto("/account/login")
page.get_by_label("Username").fill(username, timeout=5000)
page.get_by_label("Password").fill(password)
page.get_by_role("button", name="Login").click()
page.goto("/management")
return page
# # helper function for logging in the user
# def login_user(page: Page, username: str, password: str) -> Page:
# page.goto("/account/login")
# page.get_by_label("Username").fill(username, timeout=5000)
# page.get_by_label("Password").fill(password)
# page.get_by_role("button", name="Login").click()
# page.goto("/management")
# return page

def logout_user(page: Page):
page.goto("/account/logout")
page.get_by_role("button", name="Logout").click()
expect(page).to_have_url('/')
return page
# def logout_user(page: Page):
# page.goto("/account/logout")
# page.get_by_role("button", name="Logout").click()
# expect(page).to_have_url('/')
# return page

@pytest.fixture
def logged_in_user(_e2e_tests_django_db_setup, base_url_page, username:str, password: str) -> Page:
def logged_in_user(_e2e_tests_django_db_setup, django_user_model, base_url_page, client, username:str, password: str) -> Page:
"""Log in as admin user through Django login UI, returns logged in page for e2e tests."""

print()
user = django_user_model.objects.get(username=username)
print(user)
print(client)
client.force_login(user)
print(client.cookies)
session_cookie = client.cookies[settings.SESSION_COOKIE_NAME]
assert session_cookie
print(session_cookie)

# Inject the session Cookie to playwright browser:
cookie = {
'name': session_cookie.key,
'value': session_cookie.value,
# 'url': live_server_url,
}
print(cookie)

# page.context.add_cookies([cookie])


page = login_user(base_url_page, username, password)
yield page
logout_user(page)
Loading