Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
be379b8
Django 2.0 compat + tests
mpasternak Dec 10, 2017
f82c5a7
fix problem with empty slug, copy pull request https://github.com/jus…
Jun 11, 2018
4cedfbf
Merge pull request #1 from guy881/master
mpasternak Jun 25, 2018
f003e60
Bumpversion config
mpasternak Jul 13, 2018
45e3788
Branding
mpasternak Jul 13, 2018
7e25fd1
Add Python 3.6
mpasternak Jul 13, 2018
b34aa01
Use travis-tox
mpasternak Jul 13, 2018
8be49b6
Remove pypy
mpasternak Jul 13, 2018
eb1ce98
Add 3.6, remove pypy
mpasternak Jul 13, 2018
3b7e958
Bump version: 1.9.4-dev → 1.9.4
mpasternak Jul 13, 2018
90f1a8d
Rename project [skip ci]
mpasternak Jul 13, 2018
084c5fe
Sphinx 1.7.5
mpasternak Jul 13, 2018
caeabba
Add django [skip ci]
mpasternak Jul 13, 2018
f025a5e
Describe update
mpasternak Oct 21, 2019
1334f73
Merge pull request #3 from mpasternak/fix/empty-slug
mpasternak Oct 21, 2019
f4f07a4
Bump version: 1.9.4 → 1.9.5-dev
mpasternak Oct 21, 2019
e613630
Bump version: 1.9.5-dev → 1.9.5
mpasternak Oct 21, 2019
65e100f
Merge upstream/master (justinmayer/django-autoslug v1.9.9) into iplwe…
mpasternak May 8, 2026
94860a2
Convert packaging from setup.py/setup.cfg to uv + pyproject.toml
mpasternak May 8, 2026
8eca5ca
Consolidate version management with bump-my-version
mpasternak May 8, 2026
3ee821c
Add pre-commit hooks with ruff (staged files only)
mpasternak May 8, 2026
b2ddea9
Switch test runner to pytest
mpasternak May 8, 2026
1f07595
Final cleanup: gitignore patterns for pytest and ruff caches
mpasternak May 8, 2026
7878177
Remove Mercurial leftovers (.hgignore, .hgtags)
mpasternak May 8, 2026
f82dfbc
Modernize autopub deploy workflow
mpasternak May 8, 2026
f381816
Drop EOL Django/Python; support Django 5.2 LTS + 6.x
mpasternak May 8, 2026
df0f2e6
Add pyupgrade and django-upgrade pre-commit hooks
mpasternak May 8, 2026
12ed714
Fix non-idempotent slugify under Django 6.0 double pre_save
mpasternak May 8, 2026
1aa3a48
Document supported Python/Django matrix in README
mpasternak May 8, 2026
a2b94ae
Release django-autoslug-iplweb 1.9.9
botpub May 8, 2026
467c325
Serialize concurrent slug generation with select_for_update
mpasternak May 8, 2026
ea819c8
Run tests on PostgreSQL via testcontainers
mpasternak May 8, 2026
a566502
Clean up README badges
mpasternak May 8, 2026
ec6a832
Add Michał Pasternak as iplweb fork maintainer in AUTHORS.rst
mpasternak May 8, 2026
4a6d976
README: use static Python/Django version badges
mpasternak May 8, 2026
eba42ec
chore: dodaj link BuyMeACoffee do FUNDING.yml
mpasternak Jul 24, 2026
5193b8c
chore: dodaj URL Funding do pyproject.toml
mpasternak Jul 24, 2026
64e725b
feat: add Django 6.1 to the supported version matrix
mpasternak Aug 6, 2026
691527e
Merge pull request #4 from iplweb/feat/django-61
mpasternak Aug 7, 2026
04b3361
Release django-autoslug-iplweb 1.9.10
botpub Aug 7, 2026
aab7376
release: 1.10.0
mpasternak Aug 7, 2026
41f4598
chore: publish to PyPI over trusted publishing, from a tag
mpasternak Aug 7, 2026
b530654
Merge pull request #5 from iplweb/chore/trusted-publishing
mpasternak Aug 7, 2026
63a0fb2
ci: allow a release to be re-run by hand from its tag
mpasternak Aug 7, 2026
5f77895
Merge pull request #6 from iplweb/chore/manual-release-retry
mpasternak Aug 7, 2026
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
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
---

github: justinmayer
buy_me_a_coffee: mpasternak
116 changes: 59 additions & 57 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
name: build

# Tests only. Publishing lives in release.yml and is driven by a v* tag --
# see the comment at the top of that file.
on: [push, pull_request]

# Nothing here needs more than the checkout it reads.
permissions:
contents: read

env:
PYTEST_ADDOPTS: "--color=yes"

Expand All @@ -14,80 +20,76 @@ jobs:
fail-fast: false
matrix:
python-version:
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "3.14"
django-version:
- "4.2"
- "5.0"
- "5.1"
exclude:
# Django 4.2 is compatible with Python <= 3.12
- python-version: "3.13"
django-version: "4.2"
# Django 5.0 is compatible with Python 3.10, 3.11, & 3.12
- python-version: "3.9"
django-version: "5.0"
- python-version: "3.13"
django-version: "5.0"
# Django 5.1 is compatible with Python >= 3.10
- python-version: "3.9"
django-version: "5.1"
- "5.2"
- "6.0"
- "6.1"

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}

- name: Install Django
run: |
python -m pip install --upgrade pip
python -m pip install "Django~=${{ matrix.django-version }}.0"
- name: Install dependencies
run: uv sync --all-extras

- name: Pin Django to matrix version
env:
DJANGO_VERSION: ${{ matrix.django-version }}
run: uv pip install --reinstall-package django "Django~=${DJANGO_VERSION}.0"

- name: Python and Django versions
env:
PY_VERSION: ${{ matrix.python-version }}
DJ_VERSION: ${{ matrix.django-version }}
run: |
echo "Python ${{ matrix.python-version }} -> Django ${{ matrix.django-version }}"
python --version
echo "Django `django-admin --version`"

- name: Install dependencies
run: python -m pip install -r requirements/testing.txt
echo "Python ${PY_VERSION} -> Django ${DJ_VERSION}"
uv run --no-sync python --version
uv run --no-sync django-admin --version

- name: Run tests
run: coverage run --source=autoslug run_tests.py
- name: Run tests (SQLite)
run: uv run --no-sync pytest --cov=autoslug

deploy:
name: Deploy
environment: Deployment
needs: test
test-postgres:
name: Test (PostgreSQL) - Python ${{ matrix.python-version }} - Django ${{ matrix.django-version }}
runs-on: ubuntu-latest
if: github.ref=='refs/heads/master' && github.event_name!='pull_request'

strategy:
fail-fast: false
matrix:
python-version:
- "3.12"
- "3.14"
django-version:
- "5.2"
- "6.0"
- "6.1"

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: "3.9"
- name: Install uv
uses: astral-sh/setup-uv@v5

- name: Check release
id: check_release
run: |
python -m pip install poetry githubrelease httpx==0.18.2 autopub twine wheel
echo "release=$(autopub check)" >> $GITHUB_OUTPUT
- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}

- name: Publish
if: ${{ steps.check_release.outputs.release=='' }}
- name: Install dependencies
run: uv sync --all-extras

- name: Pin Django to matrix version
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
TWINE_USERNAME: "__token__"
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
git remote set-url origin https://$GITHUB_TOKEN@github.com/${{ github.repository }}
autopub deploy
DJANGO_VERSION: ${{ matrix.django-version }}
run: uv pip install --reinstall-package django "Django~=${DJANGO_VERSION}.0"

- name: Run tests (PostgreSQL via testcontainers)
env:
DJANGO_SETTINGS_MODULE: autoslug.tests.settings_postgres
run: uv run --no-sync pytest -v
200 changes: 200 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
name: Release

# Publishes to PyPI when a v* tag is pushed.
#
# Uses PyPI Trusted Publishing (OpenID Connect): GitHub mints a short-lived
# token for this exact workflow, so no API token exists in this repository to
# leak or to rotate. One-time setup on PyPI -- Manage project -> Publishing ->
# Add a new publisher:
#
# PyPI project name: django-autoslug-iplweb
# Owner: iplweb
# Repository name: django-autoslug-iplweb
# Workflow name: release.yml
# Environment name: pypi
#
# Until that publisher exists, the upload fails with
# "invalid-publisher: valid token, but no corresponding publisher".
#
# Releasing is therefore:
#
# uv run bump-my-version bump patch # rewrites the three version strings,
# # commits, and tags v<new version>
# git push && git push --tags
#
# The tag must agree with the version in the tree; the build job refuses to
# publish otherwise, because a mismatch means one of the two is a mistake and
# a wrong version cannot be taken back off PyPI.

on:
push:
tags:
- "v*"

# A release is a chain -- build, upload to PyPI, cut the GitHub release --
# and a tag pushed once fires that chain exactly once. When a later link
# breaks there is nothing left to re-trigger it: that is how tag v1.9.10 came
# to exist with a release that was never created, and the only way out was to
# delete the tag and push it again. This trigger is the way out that does not
# involve moving tags.
#
# Start it from Actions -> Release -> Run workflow with "Use workflow from"
# set to the TAG (v1.10.0, ...), never to master: every step below reads the
# version out of the ref name, and the first step of the build job refuses a
# branch rather than publish something meaningless.
workflow_dispatch:

# Read-only by default. The two jobs below widen this for themselves only.
permissions:
contents: read

jobs:
build:
name: Build distributions
runs-on: ubuntu-latest

steps:
# The dispatch dialog's "Use workflow from" list offers branches as well
# as tags, and it defaults to master. Started from a branch,
# github.ref_name is "master" rather than a version, so the tag/tree
# check below would compare the package against a tag named "master" and
# the release job would try to cut a GitHub release off a branch name.
# Stop here, and say what to do instead.
- name: Refuse to run from anything but a tag
if: github.ref_type != 'tag'
env:
REF_NAME: ${{ github.ref_name }}
REF_TYPE: ${{ github.ref_type }}
run: |
echo "::error::Started from $REF_TYPE '$REF_NAME', but this workflow releases a tagged version."
echo "::error::Re-run it from Actions -> Release -> Run workflow with 'Use workflow from' set to the TAG (e.g. v1.10.0), not to a branch."
exit 1

- uses: actions/checkout@v5

- name: Install uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0

- name: Set up Python
run: uv python install 3.13

# This package carries the version in three places -- pyproject
# `version`, autoslug/__init__.__version__ and the bumpversion
# `current_version` bookkeeping field. bump-my-version keeps them in
# step, but a hand-made tag or a half-finished bump can desynchronise
# them, and then the wheel goes out under the wrong number. Check all
# three against the tag before anything is built.
- name: Refuse to publish a tag that disagrees with the tree
env:
TAG: ${{ github.ref_name }}
run: |
uv run --no-project python - <<'PY'
import os, pathlib, re, sys, tomllib

tag = os.environ["TAG"].removeprefix("v")
pyproject = tomllib.loads(pathlib.Path("pyproject.toml").read_text())

found = {
"pyproject [project] version": pyproject["project"]["version"],
"pyproject [tool.bumpversion] current_version":
pyproject["tool"]["bumpversion"]["current_version"],
"autoslug/__init__.py __version__": re.search(
r"""^__version__ = ['"]([^'"]+)['"]""",
pathlib.Path("autoslug/__init__.py").read_text(),
re.M,
).group(1),
}

bad = {k: v for k, v in found.items() if v != tag}
for k, v in found.items():
print(f"{k}: {v}")
if bad:
for k, v in bad.items():
print(f"::error::tag {os.environ['TAG']} disagrees with {k} ({v})")
sys.exit(1)
print(f"Publishing {tag} as {os.environ['TAG']}")
PY

- name: Install dependencies
run: uv sync --all-extras

# The full Python x Django matrix already ran on master before the tag
# was pushed; this is a cheap guard against tagging a commit that was
# never green.
- name: Run the test suite (SQLite)
run: uv run --no-sync pytest -q

- name: Build sdist and wheel
run: uv build

- name: Check metadata renders on PyPI
run: uvx twine check dist/*

- uses: actions/upload-artifact@v7
with:
name: dist
path: dist/

publish:
name: Publish to PyPI
needs: build
runs-on: ubuntu-latest

# Named environment so the trusted publisher on PyPI can be scoped to it,
# and so a protection rule can gate uploads if one is ever wanted.
environment:
name: pypi
url: https://pypi.org/p/django-autoslug-iplweb

permissions:
# Required for Trusted Publishing: this is what lets GitHub mint the
# OIDC token PyPI exchanges for an upload credential. Nothing else in
# this workflow needs it, which is why publishing is its own job.
id-token: write

steps:
- uses: actions/download-artifact@v8
with:
name: dist
path: dist/

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

github-release:
name: Create the GitHub release
needs: publish
runs-on: ubuntu-latest

permissions:
contents: write # required to create the release

steps:
- uses: actions/checkout@v5

- uses: actions/download-artifact@v8
with:
name: dist
path: dist/

# Uses the workflow's own GITHUB_TOKEN. The previous autopub-based
# release used a hand-managed GH_TOKEN secret, which returned 401 and
# left tag v1.9.10 behind with nothing on PyPI; the built-in token
# cannot expire out from under the workflow.
- name: Create the release with this version's changelog section
env:
GH_TOKEN: ${{ github.token }}
run: |
version="${GITHUB_REF_NAME#v}"
# Pull just this version's section out of CHANGELOG.rst, which is
# laid out as "1.10.0 - 2026-08-07" followed by an underline.
awk -v v="$version" '
index($0, v " - ") == 1 { found = 1; underline = 1; next }
found && underline { underline = 0; next }
found && /^[0-9]+\.[0-9]+/ { exit }
found { print }
' CHANGELOG.rst > notes.md
test -s notes.md || echo "See CHANGELOG.rst." > notes.md
gh release create "$GITHUB_REF_NAME" dist/* \
--title "$GITHUB_REF_NAME" \
--notes-file notes.md
12 changes: 11 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,14 @@ docs/_build/
*.sw[op]

# Pycharm
.idea
.idea

# uv / virtualenv
.venv/
uv.lock

# pytest
.pytest_cache/

# ruff
.ruff_cache/
17 changes: 0 additions & 17 deletions .hgignore

This file was deleted.

Loading