Skip to content

Commit

Permalink
Merge branch 'master' into bump-bootstrap
Browse files Browse the repository at this point in the history
  • Loading branch information
samiashi authored Jul 11, 2024
2 parents 7368e6f + c408e99 commit f723ca1
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 52 deletions.
71 changes: 65 additions & 6 deletions .github/workflows/pre-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,18 @@ name: Deploy to test.pypi.org
on:
push:
branches: [master]
pull_request:
branches: [master]

# Only allow the latest workflow to run and cancel all others. There is also job-level concurrency
# enabled (see below), which is specified slightly differently.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
deploy:
# Build the python package even on PRs to ensure we're able to build the package properly.
build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
Expand All @@ -19,20 +28,70 @@ jobs:
- name: Install dependencies
run: python -m pip install --upgrade pip poetry

- name: Deploy to testpypi.org
- name: Building the wheels
run: |
# Using `pypi` rather than our own tags as we don't create a "release" for test version of our package.
LATEST_RELEASE=$(curl -s https://test.pypi.org/rss/project/django-jazzmin/releases.xml | sed -n 's/\s*<title>\([{a,b}0-9.]*\).*/\1/p' | head -n 2 | xargs)
# Need to check both Test PyPi and GH releases as we need to version bump the patch
# version everytime we merge in a PR, but once we release a new production release, we
# need to bump from the new release. So we grab the latest releases from both sources,
# then reverse sort them to get highest version! Simples :D
LATEST_RELEASE_TEST_PYPI=$(curl -s https://test.pypi.org/rss/project/django-jazzmin/releases.xml | sed -n 's/\s*<title>\([{a,b}0-9.]*\).*/\1/p' | head -n 2 | xargs)
LATEST_RELEASE_GITHUB=$(curl -s "https://api.github.com/repos/farridav/django-jazzmin/tags" | jq -r '.[0].name[1:]')
LATEST_RELEASE=$(printf "${LATEST_RELEASE_GITHUB}\n${LATEST_RELEASE_TEST_PYPI}" | sort -V -r | head -n 1)
# Now we can bump the version correctly to release a new version nicely base on the
# latest GH release.
poetry version $LATEST_RELEASE
poetry version prerelease # Using `prerelease` rather than `prepatch` due to a bug in Poetry (latest checked 1.8.1 - https://github.com/python-poetry/poetry/issues/879)
poetry config repositories.test_pypi https://test.pypi.org/legacy/
poetry publish --build -r test_pypi --username __token__ --password ${{ secrets.TEST_PYPI_TOKEN }} || true
poetry build
- name: Save build
uses: actions/cache/save@v4
id: build-cache
with:
path: |
dist/
key: cache-${{ github.run_id }}-${{ github.run_attempt }}

deploy:
runs-on: ubuntu-20.04
needs: build
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.x"
cache: pip

- name: Install dependencies
run: python -m pip install --upgrade pip poetry

- name: Get build
uses: actions/cache/restore@v4
with:
path: |
dist/
key: cache-${{ github.run_id }}-${{ github.run_attempt }}

- name: Configure Poetry test repo
run: poetry config repositories.test_pypi https://test.pypi.org/legacy/

- name: Deploy to testpypi.org
if: github.ref == 'refs/heads/master'
run: poetry publish -r test_pypi --dist-dir dist/ --username __token__ --password ${{ secrets.TEST_PYPI_TOKEN }} || true

- name: Deploy to testpypi.org (Dry Run)
if: github.ref != 'refs/heads/master'
run: poetry publish -r test_pypi --dist-dir dist/ --username __token__ --password ${{ secrets.TEST_PYPI_TOKEN }} || true

update_release_draft:
permissions:
contents: write
pull-requests: read
runs-on: ubuntu-latest
needs: deploy
if: github.ref == 'refs/heads/master'
steps:
- uses: release-drafter/release-drafter@v5
with:
Expand Down
6 changes: 4 additions & 2 deletions jazzmin/templatetags/jazzmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,15 +190,17 @@ def get_user_avatar(user: AbstractUser) -> str:

# If we find the property directly on the user model (imagefield or URLfield)
avatar_field = getattr(user, avatar_field_name, None)
if avatar_field:
if avatar_field is not None:
if not avatar_field:
return no_avatar
if isinstance(avatar_field, str):
return avatar_field
elif hasattr(avatar_field, "url"):
return avatar_field.url
elif callable(avatar_field):
return avatar_field()

logger.warning("avatar field must be an ImageField/URLField on the user model, or a callable")
logger.warning("Avatar field must be an ImageField/URLField on the user model, or a callable")

return no_avatar

Expand Down
126 changes: 88 additions & 38 deletions poetry.lock

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

42 changes: 36 additions & 6 deletions tests/test_templatetags.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import json
from unittest.mock import MagicMock
from unittest.mock import MagicMock, NonCallableMock

import pytest
from django.contrib.admin.models import CHANGE, LogEntry
Expand Down Expand Up @@ -50,16 +50,46 @@ def test_style_bold_first_word():

@pytest.mark.django_db
@pytest.mark.parametrize(
"case,test_input,field,expected",
"case,test_input,field,expected,log",
[
(1, MagicMock(avatar="image.jpg"), "avatar", "image.jpg"),
(2, MagicMock(avatar="image.jpg"), lambda u: u.avatar, "image.jpg"),
(3, MagicMock(avatar=MagicMock(url="image.jpg")), "avatar", "image.jpg"),
(1, MagicMock(avatar="image.jpg"), "avatar", "image.jpg", None),
(2, MagicMock(avatar="image.jpg"), lambda u: u.avatar, "image.jpg", None),
(3, MagicMock(avatar=MagicMock(url="image.jpg")), "avatar", "image.jpg", None),
# Properly set file field but empty (no image uploaded)
(
4,
MagicMock(avatar=MagicMock(__bool__=lambda x: False)),
"avatar",
"/static/vendor/adminlte/img/user2-160x160.jpg",
None,
),
# No avatar field set
(
5,
MagicMock(
avatar="image.jpg",
),
None,
"/static/vendor/adminlte/img/user2-160x160.jpg",
None,
),
# No proper avatar field set
(
6,
MagicMock(avatar=NonCallableMock(spec_set=["__bool__"], __bool__=lambda x: True)),
"avatar",
"/static/vendor/adminlte/img/user2-160x160.jpg",
"Avatar field must be",
),
],
)
def test_get_user_avatar(case, test_input, field, expected, custom_jazzmin_settings):
def test_get_user_avatar(case, test_input, field, expected, log, custom_jazzmin_settings, caplog):
"""
We can specify the name of a charfield or imagefield on our user model, or a callable that receives our user
"""
custom_jazzmin_settings["user_avatar"] = field
assert jazzmin.get_user_avatar(test_input) == expected
if log:
assert log in caplog.text
else:
assert not caplog.text

0 comments on commit f723ca1

Please sign in to comment.