Comment est constitué Django ?

Ce document explique comment est réalisée une publication de Django.

Veuillez s’il-vous-plaît garder ces instructions à jour si vous procédez à des modifications ! La clé ici est d’être descriptif et non pas normatif, sentez-vous donc libre de simplifier ou de faire d’autres changements dans la procédure, mais alors mettez à jour ce document en fonction !

Aperçu

Il peut être nécessaire d’effectuer trois différents types de publications :

  • Publications de sécurité : annonce et résolution d’une vulnérabilité. Cela implique généralement deux ou trois publications simultanées – par ex. 3.2.x, 4.0.x et selon le timing, peut-être une 4.1.x.
  • Publications de version normale : soit une publication finale (par ex. 4.1) ou une mise à jour corrective (par ex. 4.1.1).
  • Prépublications : par ex. 4.2 alpha, bêta ou rc.

La version courte des étapes à suivre est :

  1. S’il s’agit d’une publication de sécurité, prénotifier la liste de distribution de sécurité une semaine avant la publication effective.
  2. Relire les notes de publication, particulièrement en ce qui concerne leur organisation et leur formulation. Écrire un brouillon d’article de blog et de courriel d’annonce.
  3. Mettre à jour les numéros de version et créer le ou les paquets de la publication.
  4. Envoyer le ou les paquets sur le serveur djangoproject.com.
  5. Vérifier les signatures du ou des paquets, contrôler s’ils peuvent être installés et s’assurer de leur fonctionnement minimal.
  6. Envoyer la ou les nouvelles versions au serveur PyPI.
  7. Déclarer la nouvelle version dans l’interface d’administration de djangoproject.com.
  8. Publier l’article de blog et envoyer le courriel d’annonce.
  9. Mettre à jour les numéros de version après la publication.

Il y a beaucoup de détails, accrochez-vous !

Prérequis

You’ll need a few things before getting started. If this is your first release, you’ll need to coordinate with another releaser to get all these things lined up, and write to the Ops mailing list requesting the required access and permissions.

  • A Unix environment with these tools installed (in alphabetical order):

    • bash
    • git
    • GPG
    • make
    • man
    • hashing tools (typically md5sum, sha1sum, and sha256sum on Linux, or md5 and shasum on macOS)
    • python
    • ssh
  • A GPG key pair. Ensure that the private part of this key is securely stored. The public part needs to be uploaded to your GitHub account, and also to the Jenkins server running the « confirm release » job.

    Plus d’une clé GPG

    Si la clé que vous souhaitez utiliser n’est pas votre clé de signature par défaut, vous devrez ajouter -u vous@example.com à chaque commande de signature GPG affichée ci-dessous, où vous@example.com est l’adresse de courriel associée à la clé que vous allez utiliser.

  • Un environnement virtuel Python propre par version de Django à publier, avec ces paquets Python obligatoirement installés :

    $ python -m pip install build twine
    
  • Access to Django’s project on PyPI to upload binaries, ideally with extra permissions to yank a release if necessary. Create a project-scoped token following the official documentation and set up your $HOME/.pypirc file like this:

    ~/.pypirc
    [distutils]
      index-servers =
        pypi
        django
    
    [pypi]
      username = __token__
      password = # User-scoped or project-scoped token, to set as the default.
    
    [django]
      repository = https://upload.pypi.org/legacy/
      username = __token__
      password = # A project token.
    
  • Access to Django’s project on Transifex, with a Manager role. Generate an API Token in the user setting section and set up your $HOME/.transifexrc file like this:

    ~/.transifexrc
    [https://www.transifex.com]
      rest_hostname = https://rest.api.transifex.com
      token = # API token
    
  • Un accès au serveur djangoproject.com pour y envoyer des fichiers (en utilisant scp).

  • Un accès à l’interface d’administration Django de djangoproject.com comme « mainteneur de site ».

  • Access to create a post in the Django Forum - Announcements category and to send emails to the following mailing lists:

  • Access to the django-security repo in GitHub. Among other things, this provides access to the pre-notification distribution list (needed for security release preparation tasks).

Tâches de pré-publication

A few items need to be taken care of before even beginning the release process. This stuff starts about a week before the release; most of it can be done any time leading up to the actual release.

10 (or more) days before a security release

  1. Request the CVE IDs for the security issue(s) being released. One CVE ID per issue, requested with Vendor: djangoproject and Product: django.
  2. Generate the relevant (private) patch(es) using git format-patch, one for the main branch and one for each stable branch being patched.

A week before a security release

  1. Send out pre-notification exactly one week before the security release. The template for that email and a list of the recipients are in the private django-security GitHub wiki. BCC the pre-notification recipients and be sure to include the relevant CVE IDs. Attach all the relevant patches (targeting main and the stable branches) and sign the email text with the key you’ll use for the release, with a command like:

    $ gpg --clearsign --digest-algo SHA256 prenotification-email.txt
    
  2. Notify django-announce of the upcoming security release with a general message such as:

    Notice of upcoming Django security releases (3.2.24, 4.2.10 and 5.0.2)
    
    Django versions 5.0.2, 4.2.10, and 3.2.24 will be released on Tuesday,
    February 6th, 2024 around 1500 UTC. They will fix one security defect
    with severity "moderate".
    
    For details of severity levels, see:
    https://docs.djangoproject.com/en/dev/internals/security/#how-django-discloses-security-issues
    

A few days before any release

  1. À l’approche de la publication, surveiller Trac pour être sûr qu’aucun ticket de sécurité bloquant ne reste en suspens pour la publication à venir.

  2. Se coordonner avec les autres fusionneurs pour être sûr qu’ils n’ont pas de commits en attente pour cette publication.

  3. Relire les notes de publication, y compris la version en ligne pour détecter tout lien cassé ou erreur reST, et s’assurer que les notes de publication contiennent la bonne date.

  4. Revérifier que les notes de publication mentionnent la planification d’obsolescence pour toute API signalée comme obsolète et qu’elles mentionnent tout changement dans la prise en charge des versions de Python.

  5. Revérifier que le sommaire des notes de publication contienne un lien vers les notes de la nouvelle publication ; le fichier concerné est docs/releases/index.txt.

  6. S’il s’agit d’une publication principale, s’assurer que les traductions en provenance de Transifex ont été intégrées. Cette opération est parfois réalisée par un gestionnaire des traductions autre que le publicateur, mais voici les étapes à suivre. Ce processus est un peu long donc assurez-vous d’avoir 4-10 heures à y consacrer et idéalement planifiez cette tâche un ou deux jours avant le jour de la publication.

    In addition to having a configured Transifex account, the tx CLI should be available in your PATH. Then, you can fetch all the translations by running:

    $ python scripts/manage_translations.py fetch
    

    This command takes some time to run. When done, carefully inspect the output for potential errors and/or warnings. If there are some, you will need to debug and resolve them on a case by case basis.

    The recently fetched translations need some manual adjusting. First of all, the PO-Revision-Date values must be manually bumped to be later than POT-Creation-Date. You can use a command similar to this to bulk update all the .po files (compare the diff against the relevant stable branch):

    $ git diff --name-only stable/5.0.x | grep "\.po"  | xargs sed -ri "s/PO-Revision-Date: [0-9\-]+ /PO-Revision-Date: $(date -I) /g"
    

    All the new .po files should be manually and carefully inspected to avoid committing a change in a file without any new translations. Also, there shouldn’t be any changes in the « plural forms »: if there are any (usually Spanish and French report changes for this) those will need reverting.

    Lastly, commit the changed/added files (both .po and .mo) and create a new PR targeting the stable branch of the corresponding release (example PR updating translations for 4.2).

  7. Mettez à jour la page de manuel de django-admin:

    $ cd docs
    $ make man
    $ man _build/man/django-admin.1  # do a quick sanity check
    $ cp _build/man/django-admin.1 man/django-admin.1
    

    puis faites le commit de la page de manuel modifiée.

  8. S’il s’agit de la version alpha d’une nouvelle série, créez une nouvelle branche stable à partir de main. Par exemple, lors de la publication de Django 4.2 :

    $ git checkout -b stable/4.2.x origin/main
    $ git push origin -u stable/4.2.x:stable/4.2.x
    

    En même temps, mettez à jour la variable django_next_version dans docs/conf.py de la branche de publication stable pour qu’elle pointe vers la nouvelle version de développement. Par exemple, lors de la création de stable/4.2.x, définissez django_next_version à '5.0' dans la nouvelle branche.

  9. S’il s’agit de la publication « .0 » d’une nouvelle série, créez une nouvelle branche à partir de la branche stable actuelle dans le dépôt django-docs-translations. Par exemple, lors de la publication de Django 4.2 :

    $ git checkout -b stable/4.2.x origin/stable/4.1.x
    $ git push origin stable/4.2.x:stable/4.2.x
    
  10. Écrivez l’article de blog d’annonce de la publication. Vous pouvez l’écrire dans le site d’administration tout en le marquant comme inactif. Voici quelque exemples : exemple d’annonce de publication de sécurité, exemple d’annonce de publication normale, exemple d’annonce de pré-publication.

Production réelle de la nouvelle version

OK, this is the fun part, where we actually push out a release! If you’re issuing multiple releases, repeat these steps for each release.

  1. Vérifiez que Jenkins est vert pour la ou les versions que vous allez produire. Vous ne devriez probablement pas produire de version tant que ce n’est pas vert, et vous devez vous assurer que la dernière exécution en vert inclue les modifications que vous allez publier.

  2. Cleanup the release notes for this release. Make these changes in main and backport to all branches where the release notes for a particular version are located.

    1. For a feature release, remove the UNDER DEVELOPMENT header at the top of the release notes, remove the Expected prefix and update the release date, if necessary (example commit).
    2. For a patch release, remove the Expected prefix and update the release date for all releases, if necessary (example commit).
  3. A release always begins from a release branch, so you should make sure you’re on an up-to-date stable branch. Also, you should have available a clean and dedicated virtual environment per version being released. For example:

    $ git checkout stable/4.1.x
    $ git pull
    
  4. S’il s’agit d’une mise à jour de sécurité, fusionnez les correctifs appropriés à partir de django-security. Rebasez ces correctifs si nécessaire pour que chacun d’entre eux soit un commit simple sur la branche de publication plutôt qu’un commit de fusion. Pour s’assurer de cela, fusionnez-les avec le drapeau --ff-only; par exemple :

    $ git checkout stable/4.1.x
    $ git merge --ff-only security/4.1.x
    

    (Cela suppose que security/4.1.x est une branche du dépôt django-security contenant les correctifs de sécurité nécessaires pour la prochaine publication de la série 4.1).

    Si Git refuse de fusionner avec --ff-only, revenez dans la branche des correctifs de sécurité et rebasez-la sur la branche dans laquelle vous allez effectuer la fusion (git checkout security/4.1.x; git rebase stable/4.1.x), puis retournez dans la branche initiale et effectuez la fusion. Vérifiez que le message de commit de chaque correction de sécurité explique qu’il s’agit bien d’un correctif de sécurité et qu’une annonce va suivre (exemple de commit de sécurité).

  5. Mettez à jour le numéro de version dans django/__init__.py pour la publication. Veuillez lire les notes sur la définition du tuple VERSION ci-dessous pour plus de détails sur le format de VERSION (commit d’exemple).

    1. If this is a pre-release package also update the « Development Status » trove classifier in pyproject.toml to reflect this. An rc pre-release should not change the trove classifier (example commit for alpha release, example commit for beta release).
    2. Otherwise, make sure the classifier is set to Development Status :: 5 - Production/Stable.
  6. Placez une étiquette sur la publication avec git tag. Par exemple :

    $ git tag --sign --message="Tag 4.1.1" 4.1.1
    

    Vous pouvez contrôler votre travail en exécutant git tag --verify <tag>.

  7. Poussez votre travail et la nouvelle étiquette :

    $ git push
    $ git push --tags
    
  8. Assurez-vous d’avoir une arborescence parfaitement propre en exécutant git clean -dfx.

  9. Lancez python -m build` pour générer les paquets à publier. Ces paquets seront créés dans un répertoire dist/.

  10. Générez les empreintes des paquets à publier :

    $ cd dist
    $ md5sum *
    $ sha1sum *
    $ sha256sum *
    
  11. Créez un fichier « checksums », Django-<<VERSION>>.checksum.txt` contenant les empreintes et les informations de publication. Commencez avec ce modèle et insérez la version correcte, la date, l’identifiant de clé GPG (provenant de gpg --list-keys --keyid-format LONG), le nom d’utilisateur de responsable de version GitHub, l’URL de publication et les sommes de contrôle :

    This file contains MD5, SHA1, and SHA256 checksums for the source-code
    tarball and wheel files of Django <<VERSION>>, released <<DATE>>.
    
    To use this file, you will need a working install of PGP or other
    compatible public-key encryption software. You will also need to have
    the Django release manager's public key in your keyring. This key has
    the ID ``XXXXXXXXXXXXXXXX`` and can be imported from the MIT
    keyserver, for example, if using the open-source GNU Privacy Guard
    implementation of PGP:
    
        gpg --keyserver pgp.mit.edu --recv-key XXXXXXXXXXXXXXXX
    
    or via the GitHub API:
    
        curl https://github.com/<<RELEASE MANAGER GITHUB USERNAME>>.gpg | gpg --import -
    
    Once the key is imported, verify this file:
    
        gpg --verify <<THIS FILENAME>>
    
    Once you have verified this file, you can use normal MD5, SHA1, or SHA256
    checksumming applications to generate the checksums of the Django
    package and compare them to the checksums listed below.
    
    Release packages
    ================
    
    https://www.djangoproject.com/m/releases/<<MAJOR VERSION>>/<<RELEASE TAR.GZ FILENAME>>
    https://www.djangoproject.com/m/releases/<<MAJOR VERSION>>/<<RELEASE WHL FILENAME>>
    
    MD5 checksums
    =============
    
    <<MD5SUM>>  <<RELEASE TAR.GZ FILENAME>>
    <<MD5SUM>>  <<RELEASE WHL FILENAME>>
    
    SHA1 checksums
    ==============
    
    <<SHA1SUM>>  <<RELEASE TAR.GZ FILENAME>>
    <<SHA1SUM>>  <<RELEASE WHL FILENAME>>
    
    SHA256 checksums
    ================
    
    <<SHA256SUM>>  <<RELEASE TAR.GZ FILENAME>>
    <<SHA256SUM>>  <<RELEASE WHL FILENAME>>
    
  12. Signez le fichier de sommes de contrôle (gpg --clearsign --digest-algo SHA256 Django-<version>.checksum.txt). Cela produit un document signé, Django-<version>.checksum.txt.asc que vous pouvez ensuite vérifier avec gpg --verify Django-<version>.checksum.txt.asc.

Rendre la ou les publications publique(s)

Vous êtes maintenant prêt à publier les nouveaux paquets. Pour cela :

  1. Téléversez les fichiers de sommes de contrôle :

    $ scp Django-A.B.C.checksum.txt.asc djangoproject.com:/home/www/www/media/pgp/Django-A.B.C.checksum.txt
    

    (If this is a security release, what follows should be done 15 minutes before the announced release time, no sooner.)

  2. Téléversez les paquets à publier sur le serveur djangoproject, en remplaçant A.B. par le numéro de version approprié, par ex. 4.1 pour une publication 4.1.x :

    $ scp Django-* djangoproject.com:/home/www/www/media/releases/A.B
    

    If this is the alpha release of a new series, you will need to create first the directory A.B.

  3. Test that the release packages install correctly using pip. Here’s one simple method (this just tests that the binaries are available, that they install correctly, and that migrations and the development server start, but it’ll catch silly mistakes):

    $ RELEASE_VERSION='4.1.1'
    $ MAJOR_VERSION=`echo $RELEASE_VERSION| cut -c 1-3`
    
    $ python -m venv django-pip-tarball
    $ . django-pip-tarball/bin/activate
    $ python -m pip install https://www.djangoproject.com/m/releases/$MAJOR_VERSION/Django-$RELEASE_VERSION.tar.gz
    $ django-admin startproject test_tarball
    $ cd test_tarball
    $ ./manage.py --help  # Ensure executable bits
    $ python manage.py migrate
    $ python manage.py runserver
    <CTRL+C>
    $ deactivate
    $ cd .. && rm -rf test_tarball && rm -rf django-pip-tarball
    
    $ python -m venv django-pip-wheel
    $ . django-pip-wheel/bin/activate
    $ python -m pip install https://www.djangoproject.com/m/releases/$MAJOR_VERSION/Django-$RELEASE_VERSION-py3-none-any.whl
    $ django-admin startproject test_wheel
    $ cd test_wheel
    $ ./manage.py --help  # Ensure executable bits
    $ python manage.py migrate
    $ python manage.py runserver
    <CTRL+C>
    $ deactivate
    $ cd .. && rm -rf test_wheel && rm -rf django-pip-wheel
    
  4. Lancez la construction confirm-release sur Jenkins pour vérifier les fichiers de sommes de contrôle (par ex. utilisez 4.2rc1 pour https://media.djangoproject.com/pgp/Django-4.2rc1.checksum.txt).

  5. Envoyez les paquets à publier vers PyPI (pour les prépublications, n’envoyez que le fichier wheel) :

    $ twine upload dist/*
    
  6. Allez à la page d’ajout de publication dans le site d’administration, saisissez le nouveau numéro de version exactement tel qu’il apparaît dans le nom du fichier à publier (Django-<version>.tar.gz). Entrez donc par exemple « 4.1.1 » ou « 4.2rc1 », etc. Si la publication fait partie d’une branche LTS, indiquez-le.

    S’il s’agit de la version alpha d’une nouvelle série, créez aussi un objet Release pour la publication finale, en prenant soin de laisser vide le champ Release date, le marquant ainsi comme non publié. Par exemple, en créant l’objet Release pour 4.2a1, créez aussi 4.2 en laissant vide son champ de date de publication.

  7. Écrivez l’article de blog annonçant que la publication est en ligne.

  8. Pour une publication majeure (par ex. 4.1, 4.2), mettez à jour la version stable par défaut de la documentation en activant le drapeau is_default sur l’objet DocumentRelease approprié de la base de données docs.djangoproject.com (cela va automatiquement mettre à False ce drapeau pour toutes les autres instances) ; vous pouvez faire cela par le moyen du site d’administration.

    Create new DocumentRelease objects for each language that has an entry for the previous release. Update djangoproject.com’s robots.docs.txt file by copying the result generated from running the command manage_translations.py robots_txt in the current stable branch from the django-docs-translations repository. For example, when releasing Django 4.2:

    $ git checkout stable/4.2.x
    $ git pull
    $ python manage_translations.py robots_txt
    
  9. Publiez l’annonce de publication sur les listes de diffusion django-announce, django-developers et django-users ainsi que sur le Forum Django. Cette annonce doit contenir un lien vers l’article de blog de l’annonce.

  10. S’il s’agit d’une mise à jour de sécurité, envoyez un message séparé à oss-security@lists.openwall.com. Indiquez un sujet descriptif tel que par exemple « Django » suivi du titre du problème provenant des notes de publication (y compris l’ID CVE). Le corps du message doit inclure les détails de la vulnérabilité, par exemple le texte de l’article de blog de l’annonce. Incluez un lien vers cet article de blog d’annonce.

  11. Ajoutez un lien vers l’article de blog dans le sujet du canal IRC #django: /msg chanserv TOPIC #django ici le nouveau sujet.

Après la publication

Vous êtes presque au bout ! Tout ce qui reste à faire est :

  1. Mettez à jour à nouveau le tuple VERSION dans django/__init__.py, en l’incrémentant à ce que la prochaine version devra donner. Par exemple, après la publication de 4.1.1, mettez à jour VERSION à VERSION = (4, 1, 2, 'alpha', 0).
  2. Ajoutez la version dans la liste des versions de Trac si nécessaire (et, s’il s’agit d’une version finale, mettez-la comme version par défaut en modifiant le réglage default_version dans le fichier trac.ini de code.djangoproject.com). La nouvelle version X.Y doit être ajoutée après la publication alpha et la version par défaut doit être mise à jour après la publication .0.
  3. If this was a final release:
    1. Update the current stable branch and remove the pre-release branch in the Django release process on Trac.
    2. Update djangoproject.com’s download page (example PR).
  4. S’il s’est agi d’une publication de sécurité, mettez à jour Archive des issues de sécurité avec les détails sur les problèmes corrigés.

Tâches pour les nouvelles versions stables

Il y a plusieurs choses à faire à la suite de la création d’une nouvelle branche stable (suivant en général une publication alpha). Certaines de ces tâches n’ont pas besoin d’être réalisées par le publicateur.

  1. Create a new DocumentRelease object in the docs.djangoproject.com database for the new version’s docs, and update the docs/fixtures/doc_releases.json JSON fixture, so people without access to the production DB can still run an up-to-date copy of the docs site (example PR).
  2. Créez un squelette de notes de publication pour la nouvelle version majeure. Utilisez le modèle de l’ancienne version majeure ou copiez le contenu d’une précédente version majeure en supprimant la plupart de son contenu excepté les en-têtes.
  3. Augmentez le nombre d’itérations PBKDF2 par défaut dans django.contrib.auth.hashers.PBKDF2PasswordHasher d’environ 20% (en choisissant un chiffre rond). Lancez les tests et mettez à jour les 3 tests en échec liés aux empreintes avec les nouvelles valeurs. Assurez-vous que les notes de publication mentionnent cette augmentation (voir par exemple les notes de publication de la version 4.1).
  4. Enlevez les fonctionnalités qui ont atteint la fin de leur cycle d’obsolescence. Chaque suppression doit être appliquée dans un commit séparé pour plus de clarté. Dans le message de commit, ajoutez si possible la mention « refs #XXXX » pointant vers le ticket d’origine qui a provoqué l’obsolescence.
  5. Supprimez les annotations .. versionadded::, .. versionadded:: et .. deprecated:: dans la documentation concernant l’avant-dernière publication. Par exemple, dans Django 4.2, les notes pour 4.0 seront supprimées.
  6. Ajoutez la nouvelle branche sur Read the Docs. Comme les noms de versions automatiquement générés («stable-A.B.x») diffèrent des noms de versions utilisés dans Read the Docs («A.B.x»), créez un ticket demandant la nouvelle version.
  7. Demandez la nouvelle classification sur PyPI. Par exemple, Framework :: Django :: 3.1.
  8. Mettez à jour la version de développement active à la branche actuelle et ajoutez la branche de pré-publication dans le processus de publication de Django sur Trac.

Notes sur la définition du tuple VERSION

La version de Django est contrôlée par le tuple VERSION dans django/__init__.py. C’est un tuple à cinq éléments, contenant :

  1. La version majeure.
  2. La version mineure.
  3. La version micro.
  4. Le statut, qui peut-être « alpha », « beta », « rc » ou « final ».
  5. Le numéro de série, dans le cas des versions alpha/beta/RC qui se font suite (autorisant, par exemple, « beta 1 », « beta 2 », etc.).

Pour une version finale, le statut est toujours « final » et le numéro de série 0. Un numéro de série à 0 avec le statut « alpha » est signalé comme une « pre-alpha ».

Quelques exemples :

  • (4, 1, 1, "final", 0) → « 4.1.1 »
  • (4, 2, 0, "alpha", 0) → « 4.2 pre-alpha »
  • (4, 2, 0, "beta", 1) → « 4.2 beta 1 »
Back to Top