mirror of
https://github.com/django/django.git
synced 2025-03-13 02:40:47 +00:00
Updated docs for the Django release process.
This commit is contained in:
parent
34f329ecac
commit
1a36dce9c5
@ -50,22 +50,46 @@ There are a lot of details, so please read on.
|
|||||||
Prerequisites
|
Prerequisites
|
||||||
=============
|
=============
|
||||||
|
|
||||||
You'll need a few things before getting started:
|
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 GPG key. If the key you want to use is not your default signing key, you'll
|
* A Unix environment with these tools installed (in alphabetical order):
|
||||||
need to add ``-u you@example.com`` to every GPG signing command below, where
|
|
||||||
``you@example.com`` is the email address associated with the key you want to
|
|
||||||
use. You will also need to add ``-i you@example.com`` to the ``twine`` call.
|
|
||||||
|
|
||||||
* An install of some required Python packages:
|
* 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.
|
||||||
|
|
||||||
|
.. admonition:: More than one GPG key
|
||||||
|
|
||||||
|
If the key you want to use is not your default signing key, you'll need to
|
||||||
|
add ``-u you@example.com`` to every GPG signing command shown below, where
|
||||||
|
``you@example.com`` is the email address associated with the key you want
|
||||||
|
to use.
|
||||||
|
|
||||||
|
* A clean Python virtual environment per Django version being released, with
|
||||||
|
these required Python packages installed:
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
$ python -m pip install wheel twine
|
$ python -m pip install wheel twine
|
||||||
|
|
||||||
* Access to Django's project on PyPI. Create a project-scoped token following
|
* Access to `Django's project on PyPI <https://pypi.org/project/Django/>`_ to
|
||||||
the `official documentation <https://pypi.org/help/#apitoken>`_ and set up
|
upload binaries, ideally with extra permissions to `yank a release
|
||||||
your ``$HOME/.pypirc`` file like this:
|
<https://pypi.org/help/#yanked>`_ if necessary. Create a project-scoped token
|
||||||
|
following the `official documentation <https://pypi.org/help/#apitoken>`_
|
||||||
|
and set up your ``$HOME/.pypirc`` file like this:
|
||||||
|
|
||||||
.. code-block:: ini
|
.. code-block:: ini
|
||||||
:caption: ``~/.pypirc``
|
:caption: ``~/.pypirc``
|
||||||
@ -84,7 +108,7 @@ You'll need a few things before getting started:
|
|||||||
username = __token__
|
username = __token__
|
||||||
password = # A project token.
|
password = # A project token.
|
||||||
|
|
||||||
* Access to Django's project on `Transifex
|
* Access to `Django's project on Transifex
|
||||||
<https://app.transifex.com/django/django/>`_, with a Manager role. Generate
|
<https://app.transifex.com/django/django/>`_, with a Manager role. Generate
|
||||||
an API Token in the `user setting section
|
an API Token in the `user setting section
|
||||||
<https://app.transifex.com/user/settings/api/>`_ and set up your
|
<https://app.transifex.com/user/settings/api/>`_ and set up your
|
||||||
@ -97,33 +121,69 @@ You'll need a few things before getting started:
|
|||||||
rest_hostname = https://rest.api.transifex.com
|
rest_hostname = https://rest.api.transifex.com
|
||||||
token = # API token
|
token = # API token
|
||||||
|
|
||||||
* Access to the ``djangoproject.com`` server to upload files.
|
* Access to the ``djangoproject.com`` server to upload files (using ``scp``).
|
||||||
|
|
||||||
* Access to the admin on ``djangoproject.com`` as a "Site maintainer".
|
* Access to the Django admin on ``djangoproject.com`` as a "Site maintainer".
|
||||||
|
|
||||||
* Access to post to ``django-announce``.
|
* Access to create a post in the `Django Forum - Announcements category
|
||||||
|
<https://forum.djangoproject.com/c/announcements/7>`_ and to send emails to
|
||||||
|
the following mailing lists:
|
||||||
|
|
||||||
* If this is a security release, access to the pre-notification distribution
|
* `django-users <https://groups.google.com/g/django-users/>`_
|
||||||
list.
|
* `django-developers <https://groups.google.com/g/django-developers/>`_
|
||||||
|
* `django-announce <https://groups.google.com/g/django-announce/>`_
|
||||||
|
|
||||||
If this is your first release, you'll need to coordinate with another releaser
|
* Access to the ``django-security`` repo in GitHub. Among other things, this
|
||||||
to get all these things lined up.
|
provides access to the pre-notification distribution list (needed for
|
||||||
|
security release preparation tasks).
|
||||||
|
|
||||||
Pre-release tasks
|
Pre-release tasks
|
||||||
=================
|
=================
|
||||||
|
|
||||||
A few items need to be taken care of before even beginning the release process.
|
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
|
This stuff starts about a week before the release; most of it can be done
|
||||||
any time leading up to the actual release:
|
any time leading up to the actual release.
|
||||||
|
|
||||||
#. If this is a security release, send out pre-notification **one week** before
|
10 (or more) days before a security release
|
||||||
the 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. Sign the email with the key you'll use for the release and
|
#. Request the `CVE IDs <https://cveform.mitre.org/>`_ for the security
|
||||||
include `CVE IDs <https://cveform.mitre.org/>`_ (requested with Vendor:
|
issue(s) being released. One CVE ID per issue, requested with
|
||||||
djangoproject, Product: django) and patches for each issue being fixed.
|
``Vendor: djangoproject`` and ``Product: django``.
|
||||||
Also, :ref:`notify django-announce <security-disclosure>` of the upcoming
|
|
||||||
security release.
|
#. 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
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
#. 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:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ gpg --clearsign --digest-algo SHA256 prenotification-email.txt
|
||||||
|
|
||||||
|
#. :ref:`Notify django-announce <security-disclosure>` of the upcoming
|
||||||
|
security release with a general message such as:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
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
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
#. As the release approaches, watch Trac to make sure no release blockers
|
#. As the release approaches, watch Trac to make sure no release blockers
|
||||||
are left for the upcoming release.
|
are left for the upcoming release.
|
||||||
@ -214,13 +274,10 @@ any time leading up to the actual release:
|
|||||||
$ git checkout -b stable/4.2.x origin/stable/4.1.x
|
$ git checkout -b stable/4.2.x origin/stable/4.1.x
|
||||||
$ git push origin stable/4.2.x:stable/4.2.x
|
$ git push origin stable/4.2.x:stable/4.2.x
|
||||||
|
|
||||||
Preparing for release
|
#. Write the announcement blog post for the release. You can enter it into the
|
||||||
=====================
|
admin at any time and mark it as inactive. Here are a few examples: `example
|
||||||
|
security release announcement`__, `example regular release announcement`__,
|
||||||
Write the announcement blog post for the release. You can enter it into the
|
`example pre-release announcement`__.
|
||||||
admin at any time and mark it as inactive. Here are a few examples: `example
|
|
||||||
security release announcement`__, `example regular release announcement`__,
|
|
||||||
`example pre-release announcement`__.
|
|
||||||
|
|
||||||
__ https://www.djangoproject.com/weblog/2013/feb/19/security/
|
__ https://www.djangoproject.com/weblog/2013/feb/19/security/
|
||||||
__ https://www.djangoproject.com/weblog/2012/mar/23/14/
|
__ https://www.djangoproject.com/weblog/2012/mar/23/14/
|
||||||
@ -229,15 +286,32 @@ __ https://www.djangoproject.com/weblog/2012/nov/27/15-beta-1/
|
|||||||
Actually rolling the release
|
Actually rolling the release
|
||||||
============================
|
============================
|
||||||
|
|
||||||
OK, this is the fun part, where we actually push out a release!
|
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.
|
||||||
|
|
||||||
#. Check `Jenkins`__ is green for the version(s) you're putting out. You
|
#. Check `Jenkins`__ is green for the version(s) you're putting out. You
|
||||||
probably shouldn't issue a release until it's green.
|
probably shouldn't issue a release until it's green, and you should make
|
||||||
|
sure that the latest green run includes the changes that you are releasing.
|
||||||
|
|
||||||
__ https://djangoci.com
|
__ https://djangoci.com
|
||||||
|
|
||||||
|
#. 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.
|
||||||
|
|
||||||
|
#. 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 (:commit:`example commit
|
||||||
|
<1994a2643881a9e3f9fa8d3e0794c1a9933a1831>`).
|
||||||
|
|
||||||
|
#. For a patch release, remove the ``Expected`` prefix and update the
|
||||||
|
release date for all releases, if necessary (:commit:`example commit
|
||||||
|
<34a503162fe222033a1cd3249bccad014fcd1d20>`).
|
||||||
|
|
||||||
#. A release always begins from a release branch, so you should make sure
|
#. A release always begins from a release branch, so you should make sure
|
||||||
you're on a stable branch and up-to-date. For example:
|
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:
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
@ -265,19 +339,19 @@ OK, this is the fun part, where we actually push out a release!
|
|||||||
that the commit is a security fix and that an announcement will follow
|
that the commit is a security fix and that an announcement will follow
|
||||||
(:commit:`example security commit <bf39978a53f117ca02e9a0c78b76664a41a54745>`).
|
(:commit:`example security commit <bf39978a53f117ca02e9a0c78b76664a41a54745>`).
|
||||||
|
|
||||||
#. For a feature release, remove the ``UNDER DEVELOPMENT`` header at the
|
|
||||||
top of the release notes and add the release date on the next line. For a
|
|
||||||
patch release, remove the ``Expected`` prefix and update the release date,
|
|
||||||
if necessary. Make this change on all branches where the release notes for a
|
|
||||||
particular version are located.
|
|
||||||
|
|
||||||
#. Update the version number in ``django/__init__.py`` for the release.
|
#. Update the version number in ``django/__init__.py`` for the release.
|
||||||
Please see `notes on setting the VERSION tuple`_ below for details
|
Please see `notes on setting the VERSION tuple`_ below for details
|
||||||
on ``VERSION``.
|
on ``VERSION`` (:commit:`example commit
|
||||||
|
<2719a7f8c161233f45d34b624a9df9392c86cc1b>`).
|
||||||
|
|
||||||
#. If this is a pre-release package, update the "Development Status" trove
|
#. If this is a pre-release package also update the "Development Status"
|
||||||
classifier in ``setup.cfg`` to reflect this. Otherwise, make sure the
|
trove classifier in ``setup.cfg`` to reflect this. An ``rc`` pre-release
|
||||||
classifier is set to ``Development Status :: 5 - Production/Stable``.
|
should not change the trove classifier (:commit:`example commit for alpha
|
||||||
|
release <eeeacc52a967234e920c001b7908c4acdfd7a848>`, :commit:`example
|
||||||
|
commit for beta release <25fec8940b24107e21314ab6616e18ce8dec1c1c>`).
|
||||||
|
|
||||||
|
#. Otherwise, make sure the classifier is set to
|
||||||
|
``Development Status :: 5 - Production/Stable``.
|
||||||
|
|
||||||
#. Tag the release using ``git tag``. For example:
|
#. Tag the release using ``git tag``. For example:
|
||||||
|
|
||||||
@ -285,9 +359,14 @@ OK, this is the fun part, where we actually push out a release!
|
|||||||
|
|
||||||
$ git tag --sign --message="Tag 4.1.1" 4.1.1
|
$ git tag --sign --message="Tag 4.1.1" 4.1.1
|
||||||
|
|
||||||
You can check your work by running ``git tag --verify <tag>``.
|
You can check your work running ``git tag --verify <tag>``.
|
||||||
|
|
||||||
#. Push your work, including the tag: ``git push --tags``.
|
#. Push your work and the new tag:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ git push
|
||||||
|
$ git push --tags
|
||||||
|
|
||||||
#. Make sure you have an absolutely clean tree by running ``git clean -dfx``.
|
#. Make sure you have an absolutely clean tree by running ``git clean -dfx``.
|
||||||
|
|
||||||
@ -364,13 +443,20 @@ OK, this is the fun part, where we actually push out a release!
|
|||||||
``Django-<version>.checksum.txt.asc`` which you can then verify using ``gpg
|
``Django-<version>.checksum.txt.asc`` which you can then verify using ``gpg
|
||||||
--verify Django-<version>.checksum.txt.asc``.
|
--verify Django-<version>.checksum.txt.asc``.
|
||||||
|
|
||||||
If you're issuing multiple releases, repeat these steps for each release.
|
|
||||||
|
|
||||||
Making the release(s) available to the public
|
Making the release(s) available to the public
|
||||||
=============================================
|
=============================================
|
||||||
|
|
||||||
Now you're ready to actually put the release out there. To do this:
|
Now you're ready to actually put the release out there. To do this:
|
||||||
|
|
||||||
|
#. Upload the checksum file(s):
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ 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.)
|
||||||
|
|
||||||
#. Upload the release package(s) to the djangoproject server, replacing
|
#. Upload the release package(s) to the djangoproject server, replacing
|
||||||
A.B. with the appropriate version number, e.g. 4.1 for a 4.1.x release:
|
A.B. with the appropriate version number, e.g. 4.1 for a 4.1.x release:
|
||||||
|
|
||||||
@ -378,34 +464,42 @@ Now you're ready to actually put the release out there. To do this:
|
|||||||
|
|
||||||
$ scp Django-* djangoproject.com:/home/www/www/media/releases/A.B
|
$ 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 the
|
If this is the alpha release of a new series, you will need to create
|
||||||
directory A.B.
|
**first** the directory A.B.
|
||||||
|
|
||||||
#. Upload the checksum file(s):
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
$ scp Django-A.B.C.checksum.txt.asc djangoproject.com:/home/www/www/media/pgp/Django-A.B.C.checksum.txt
|
|
||||||
|
|
||||||
#. Test that the release packages install correctly using ``pip``. Here's one
|
#. Test that the release packages install correctly using ``pip``. Here's one
|
||||||
method:
|
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):
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
$ RELEASE_VERSION='4.1.1'
|
$ RELEASE_VERSION='4.1.1'
|
||||||
$ MAJOR_VERSION=`echo $RELEASE_VERSION| cut -c 1-3`
|
$ MAJOR_VERSION=`echo $RELEASE_VERSION| cut -c 1-3`
|
||||||
|
|
||||||
$ python -m venv django-pip
|
$ python -m venv django-pip-tarball
|
||||||
$ . django-pip/bin/activate
|
$ . django-pip-tarball/bin/activate
|
||||||
$ python -m pip install https://www.djangoproject.com/m/releases/$MAJOR_VERSION/Django-$RELEASE_VERSION.tar.gz
|
$ 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
|
$ deactivate
|
||||||
|
$ cd .. && rm -rf test_tarball && rm -rf django-pip-tarball
|
||||||
|
|
||||||
$ python -m venv django-pip-wheel
|
$ python -m venv django-pip-wheel
|
||||||
$ . django-pip-wheel/bin/activate
|
$ . django-pip-wheel/bin/activate
|
||||||
$ python -m pip install https://www.djangoproject.com/m/releases/$MAJOR_VERSION/Django-$RELEASE_VERSION-py3-none-any.whl
|
$ 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
|
$ deactivate
|
||||||
|
$ cd .. && rm -rf test_wheel && rm -rf django-pip-wheel
|
||||||
This just tests that the tarballs are available (i.e. redirects are up) and
|
|
||||||
that they install correctly, but it'll catch silly mistakes.
|
|
||||||
|
|
||||||
#. Run the `confirm-release`__ build on Jenkins to verify the checksum file(s)
|
#. Run the `confirm-release`__ build on Jenkins to verify the checksum file(s)
|
||||||
(e.g. use ``4.2rc1`` for
|
(e.g. use ``4.2rc1`` for
|
||||||
@ -418,7 +512,7 @@ Now you're ready to actually put the release out there. To do this:
|
|||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
$ twine upload -s dist/*
|
$ twine upload dist/*
|
||||||
|
|
||||||
#. Go to the `Add release page in the admin`__, enter the new release number
|
#. Go to the `Add release page in the admin`__, enter the new release number
|
||||||
exactly as it appears in the name of the tarball
|
exactly as it appears in the name of the tarball
|
||||||
|
Loading…
x
Reference in New Issue
Block a user