Как освободить Django¶
Этот документ объясняет, как выпустить Django.
Пожалуйста, обновляйте эти инструкции, если вы вносите изменения!**Смысл здесь в том, чтобы быть описательным, а не предписывающим, поэтому не стесняйтесь упрощать или вносить другие изменения, но **обновляйте этот документ соответствующим образом!
Быстрый обзор¶
Существует три типа релизов, которые вам могут понадобиться:
- Релизы безопасности: раскрытие и устранение уязвимости. Как правило, это два или три одновременных релиза - например, 3.2.x, 4.0.x и, в зависимости от сроков, возможно, 4.1.x.
- Регулярные выпуски версий: либо финальный релиз (например, 4.1), либо обновление с исправлением ошибок (например, 4.1.1).
- Предварительные версии: например, 4.2 alpha, beta или rc.
Краткая версия действий такова:
- Если это релиз безопасности, предварительно оповестите список рассылки безопасности за неделю до фактического релиза.
- Вычитайте примечания к выпуску, ищите организационные и письменные ошибки. Составьте проект сообщения в блоге и объявления по электронной почте.
- Обновите номера версий и создайте артефакты выпуска.
- Создайте новый
Release
в окне администратора наdjangoproject.com
.- Установите правильную дату, но убедитесь, что флажок
is_active
отключен. - Загрузите артефакты (архив, колесо и контрольные суммы).
- Установите правильную дату, но убедитесь, что флажок
- Проверьте подписи пакетов, убедитесь, что они могут быть установлены, и обеспечьте минимальную функциональность.
- Загрузите новую версию(и) в PyPI.
- Включите флаг
is_active
для каждого выпуска в разделе «Администратор» наdjangoproject.com
. - Опубликуйте запись в блоге и разошлите объявления по электронной почте.
- Обновляйте номера версий после выпуска в стабильных ветвях.
- Добавьте примечания к выпуску заглушки для следующего выпуска исправления в
main
и backport.
Подробностей очень много, поэтому читайте дальше.
Пререквизиты¶
Прежде чем приступить к работе, вам понадобится кое-что уточнить. Если это ваш первый релиз, вам нужно будет согласовать это с другим разработчиком, чтобы все согласовать, и написать в список рассылки Ops с запросом необходимого доступа и разрешений.
Среда Unix с установленными этими инструментами (в алфавитном порядке):
- удар
- мерзавец
- GPG
- делать
- человек
- инструменты хэширования (обычно
md5sum
,sha1sum
, иsha256sum
в Linux илиmd5
иshasum
в macOS) - питон
Пара ключей GPG. Убедитесь, что закрытая часть этого ключа надежно сохранена. Общедоступную часть необходимо загрузить в вашу учетную запись на GitHub, а также на сервер Jenkins, на котором выполняется задание «подтвердить выпуск».
Более одного ключа GPG
Если ключ, который вы хотите использовать, не является вашим ключом подписи по умолчанию, вам нужно будет добавить
-u you@example.com
к каждой команде подписи GPG, показанной ниже, гдеyou@example.com
- это адрес электронной почты, связанный с ключом, который вы хотите использовать.Выпускается чистая виртуальная среда Python для каждой версии Django с установленными необходимыми пакетами Python:
$ python -m pip install build twine
Доступ к Django’s project on PyPI для загрузки двоичных файлов, в идеале с дополнительными правами доступа к yank a release, если это необходимо. Создайте токен в рамках проекта, следуя official documentation, и настройте свой файл
$HOME/.pypirc
следующим образом:~/.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.
Доступ к Django’s project on Transifex с ролью менеджера. Сгенерируйте токен API в user setting section и настройте свой файл
$HOME/.transifexrc
следующим образом:~/.transifexrc
¶[https://www.transifex.com] rest_hostname = https://rest.api.transifex.com token = # API token
Доступ к администратору Django на
djangoproject.com
в качестве «сопровождающего сайта».Доступ для создания записи в Django Forum - Announcements category и отправки электронных писем в список рассылки django-announce.
Доступ к репозиторию
django-security
на GitHub. Помимо прочего, это обеспечивает доступ к списку рассылки предварительных уведомлений (необходим для задач подготовки выпуска безопасности).Доступ к проекту Django на Read the Docs.
Предрелизные задачи¶
Необходимо решить несколько вопросов еще до начала процесса выпуска. Этот процесс начинается примерно за неделю до релиза; большую часть работы можно выполнить в любое время до самого выпуска.
за 10 (или более) дней до выпуска информации о безопасности¶
- Запросите CVE IDs для устранения проблемы(проблем) безопасности. Один идентификатор CVE для каждой проблемы, запрашиваемый с помощью
Vendor: djangoproject
иProduct: django
. - Сгенерируйте соответствующие (частные) исправления, используя
git format-patch
, по одному для ветвиmain
и по одному для каждой исправляемой стабильной ветви.
За неделю до выпуска секретной информации¶
Отправьте предварительное уведомление ровно за неделю до выпуска системы безопасности. Шаблон для этого электронного письма и список получателей находятся в закрытой
django-security
вики-странице на GitHub. Укажите получателей предварительного уведомления и обязательно укажите соответствующие идентификаторы CVE. Приложите все необходимые исправления (дляmain
и стабильных версий) и подпишите текст электронного письма ключом, который вы будете использовать для выпуска, командой типа:$ gpg --clearsign --digest-algo SHA256 prenotification-email.txt
Notify django-announce о предстоящем выпуске системы безопасности с общим сообщением, таким как:
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
За несколько дней до любого релиза¶
По мере приближения выпуска следите за Trac, чтобы убедиться, что для следующего выпуска не осталось блокировщиков выпуска. В исключительных обстоятельствах, например, для соблюдения заранее установленной даты выпуска системы безопасности, выпуск все еще может быть запущен с открытым блокировщиком выпуска. Лицу, осуществляющему выпуск, доверяется принятие решения о выпуске с открытым блокиратором выпуска или, при необходимости, о переносе даты выпуска выпуска, не связанного с безопасностью.
Проверьте других участников слияния, чтобы убедиться, что у них нет незафиксированных изменений для релиза.
Вычитайте примечания к выпуску, включая просмотр онлайн-версии на предмет ошибок catch any broken links или reST, и убедитесь, что в примечаниях к выпуску указана правильная дата.
Дважды проверьте, чтобы в примечаниях к выпуску были указаны сроки устаревания всех API, отмеченных как устаревшие, и чтобы в них упоминались любые изменения в поддержке версии Python.
Дважды проверьте, что в индексе примечаний к выпуску есть ссылка на примечания к новому выпуску; она будет находиться в
docs/releases/index.txt
.Если это feature release, убедитесь, что переводы из Transifex были интегрированы. Обычно это выполняется отдельным менеджером по переводу, а не разработчиком, но вот шаги, которые необходимо выполнить. Этот процесс немного затянут, поэтому обязательно выделите на это 4-10 часов, а в идеале запланируйте выполнение этой задачи за один-два дня до релиза.
В дополнение к настроенной учетной записи Transifex, tx CLI должен быть доступен в вашем
PATH
. Затем вы можете получить все переводы, выполнив:$ python scripts/manage_translations.py fetch
Выполнение этой команды занимает некоторое время. По завершении внимательно проверьте выходные данные на предмет возможных ошибок и/или предупреждений. Если таковые имеются, вам нужно будет отладить и устранить их в каждом конкретном случае.
Недавно полученные переводы требуют некоторой корректировки вручную. Прежде всего, значения
PO-Revision-Date
должны быть изменены вручную, чтобы они были более поздними, чемPOT-Creation-Date
. Вы можете использовать команду, аналогичную этой, для массового обновления всех файлов.po
(сравните разницу с соответствующей стабильной веткой).:$ 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"
Все новые файлы
.po
должны быть тщательно проверены вручную, чтобы избежать внесения изменений в файл без каких-либо новых переводов. Кроме того, не должно быть никаких изменений в «формах множественного числа»: если таковые и есть (обычно испанцы и французы сообщают об изменениях по этому поводу), их нужно будет вернуть.Наконец, зафиксируйте измененные/добавленные файлы (как
.po
, так и.mo
) и создайте новый PR, ориентированный на стабильную ветку соответствующего выпуска (пример PR updating translations for 4.2).Update the django-admin manual page:
$ 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
и затем зафиксируйте измененную страницу руководства.
Если это «нулевой» релиз новой серии, создайте новую ветку от текущей стабильной ветки в репозитории django-docs-translations. Например, при выпуске 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
Напишите анонсирующую запись в блоге для релиза. Вы можете ввести его в админку в любое время и пометить как неактивный. Вот несколько примеров: пример анонса релиза безопасности, пример анонса обычного релиза, пример анонса предварительного релиза.
За несколько дней до приостановки работы функции¶
При подготовке к альфа-релизу на сервере djangoproject должен быть создан каталог /home/www/www/media/releases/A.B
.
Перед замораживанием функций необходимо создать ветвь, ориентированную на main
, для подготовки к следующему выпуску функций. Ее следует просмотреть и утвердить за несколько дней до замораживания, что позволит объединить ее после сокращения стабильной ветви. В этой ветви следует рассмотреть следующие вопросы:
- Обновите кортеж
VERSION
вdjango/__init__.py
, увеличивая его до следующего ожидаемого выпуска (example commit). - Создайте справку о выпуске заглушки для следующего выпуска компонента. Используйте заглушку из предыдущего выпуска компонента или скопируйте содержимое из текущей версии и удалите большую часть содержимого, оставив только заголовки (example commit).
- Удалите аннотации
.. versionadded::
и.. versionchanged::
из документации двух предыдущих выпусков, а также все оставшиеся более старые аннотации. Например, в Django 5.1 примечания для версии 4.2 будут удалены (example commit). - Удалите компоненты, срок действия которых истек, включая их документы и аннотацию
.. deprecated::
. Для большей ясности каждое удаление должно выполняться в отдельном коммите. В сообщении о фиксации добавьте префиксRefs #XXXXX --
, указывающий на исходный запрос, с которого началось удаление, если это возможно. Убедитесь, что это указано в разделе «Удаленные функции» в примечаниях к выпуску (example commit). - Увеличьте количество итераций PBKDF2 по умолчанию в
django.contrib.auth.hashers.PBKDF2PasswordHasher
примерно на 20% (выберите круглое число). Запустите тесты и обновите 3 неудачных теста для хэширования новыми значениями. Убедитесь, что это указано в примечаниях к выпуску (example commit).
Конкретные примеры для ветвей начальной загрузки прошлых выпусков функций: 5.2 bootstrap, 5.1 bootstrap, 5.0 bootstrap.
Задачи по замораживанию функций¶
Удалите пустые разделы из примечаний к выпуску (example commit).
Создайте примечания к выпуску локально и прочитайте их. Внесите все необходимые изменения, чтобы улучшить поток или исправить грамматику (example commit).
Создайте новую стабильную ветку из
main
. Например, при замораживании функции Django 5.2:$ git checkout -b stable/5.2.x upstream/main $ git push upstream -u stable/5.2.x:stable/5.2.x
В то же время обновите переменную
django_next_version
вdocs/conf.py
в ветке стабильного выпуска, чтобы указать на новую версию для разработки. Например, при созданииstable/5.2.x
установите дляdjango_next_version
значение'6.0'
в новой стабильной ветке (example commit).Перейдите к Add release page in the admin, создайте объект
Release
для окончательного выпуска, убедитесь, что поле Дата выпуска пусто, и пометьте его как неизданный. Например, при созданииstable/5.2.x
создайте5.2
с пустым полем даты выпуска. Если выпуск является частью ветви LTS, отметьте его таким образом.Перейдите к Add document release page in the admin, создайте новый объект
DocumentRelease
для английского языка для вновь созданного объектаRelease
. Не отмечайте это как значение по умолчанию.Добавьте новую ветвь в Read the Docs. Поскольку автоматически сгенерированные имена версий («stable-A.B.x») отличаются от имен версий, используемых в Read the Docs («A.B.x»), create a ticket запрашивает новую версию.
Request the new classifier on PyPI. Например,
Framework :: Django :: 5.2
.Создайте roadmap page для следующего релиза, который будет опубликован в ближайшее время. Чтобы создать новую страницу в Вики, перейдите по URL-адресу, где вы хотите создать страницу, и будет доступна кнопка «Создать эту страницу».
Обновите текущую ветку, находящуюся в активной разработке, и добавьте предрелизную ветку в Django release process на Trac.
Обновите
docs/fixtures/doc_releases.json
JSON-файл для djangoproject.com, чтобы люди, не имеющие доступа к рабочей базе данных, могли по-прежнему запускать обновленную копию сайта docs (example PR). Это будет объединено после окончательного выпуска.
Фактическое развертывание релиза¶
Итак, это самая интересная часть, когда мы действительно выпускаем релиз! Если вы выпускаете ** несколько релизов **, повторите эти шаги для каждого релиза.
Отметьте, что Jenkins имеет зеленый цвет для версий, которые вы выпускаете. Вероятно, вам не следует выпускать релиз, пока он не станет зеленым, и вы должны убедиться, что последний зеленый выпуск включает изменения, которые вы выпускаете.
Очистите примечания к выпуску для этого выпуска. Внесите эти изменения в
main
и перенесите их во все разделы, где находятся примечания к выпуску для конкретной версии.- Для выпуска новой функции удалите заголовок
UNDER DEVELOPMENT
в верхней части примечаний к выпуску, уберите префиксExpected
и при необходимости обновите дату выпуска (example commit). - Для выпуска исправления удалите префикс
Expected
и при необходимости обновите дату выпуска для всех выпусков (example commit).
- Для выпуска новой функции удалите заголовок
Выпуск всегда начинается с ветки release, поэтому вам следует убедиться, что вы используете обновленную стабильную ветку. Кроме того, у вас должна быть доступна чистая и выделенная версия виртуальной среды, которая будет выпущена. Например:
$ git checkout stable/4.1.x $ git pull
Если это релиз безопасности, слейте соответствующие патчи из
django-security
. Перезалейте эти патчи по мере необходимости, чтобы каждый из них стал обычным коммитом в ветке релиза, а не коммитом слияния. Для этого объедините их с флагом--ff-only
; например:$ git checkout stable/4.1.x $ git merge --ff-only security/4.1.x
(При этом предполагается, что
security/4.1.x
- это ветка в репозиторииdjango-security
, содержащая необходимые исправления безопасности для следующего выпуска серии 4.1).Если git отказывается сливаться с
--ff-only
, переключитесь на ветку security-patch и перебазируйте ее на ветку, с которой вы собираетесь слиться (git checkout security/4.1.x; git rebase stable/4.1.x
), а затем переключитесь обратно и выполните слияние. Убедитесь, что сообщение о фиксации каждого исправления безопасности объясняет, что фиксация является исправлением безопасности и что за ней последует объявление (example security commit).Обновите номер версии в
django/__init__.py
для выпуска. Пожалуйста, смотрите notes on setting the VERSION tuple ниже для получения подробной информации оVERSION
(example commit).- Если это предварительный выпуск пакета, также обновите классификатор находок «Статус разработки» в
pyproject.toml
, чтобы отразить это. Предварительный выпускrc
не должен изменять классификатор сокровищ (example commit for alpha release, example commit for beta release). - В противном случае убедитесь, что для классификатора установлено значение
Development Status :: 5 - Production/Stable
.
- Если это предварительный выпуск пакета, также обновите классификатор находок «Статус разработки» в
Создание артефактов¶
При необходимости используйте вспомогательные скрипты
Вы можете упростить некоторые из приведенных ниже шагов, используя вспомогательные скрипты из Wiki:
Пометьте релиз с помощью метки
git tag
. Например:$ git tag --sign --message="Tag 4.1.1" 4.1.1
Вы можете проверить, выполняется ли ваша работа
git tag --verify <tag>
.Убедитесь, что у вас абсолютно чистое дерево, выполнив
git clean -dfx
.Запустите
python -m build
, чтобы сгенерировать пакеты выпуска. Это создаст артефакты выпуска (архиватор и колесо) в каталогеdist/
. Для Django версии 5.0 или старше вам нужно запуститьmake -f extras/Makefile
вместо этого.Сгенерировать хэши пакетов релиза:
$ cd dist $ md5sum * $ sha1sum * $ sha256sum *
Создайте файл «checksums»,
Django-<<VERSION>>.checksum.txt
содержащий хэши и информацию о релизе. Начните с этого шаблона и вставьте правильную версию, дату, идентификатор ключа GPG (изgpg --list-keys --keyid-format LONG
), имя пользователя GitHub менеджера релиза, URL релиза и контрольные суммы: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/download/<<VERSION>>/tarball/ https://www.djangoproject.com/download/<<VERSION>>/wheel/ 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>>
Подпишите файл контрольной суммы (
gpg --clearsign --digest-algo SHA256 Django-<version>.checksum.txt
). В результате создается подписанный документDjango-<version>.checksum.txt.asc
, который затем можно проверить с помощьюgpg --verify Django-<version>.checksum.txt.asc
.
Сделать релиз(ы) доступным для общественности¶
Теперь вы готовы выпустить релиз в свет. Для этого:
Создайте новую запись
Release
в поле djangoproject.com’s admin. Если это обновление системы безопасности, это следует сделать за 15 минут до объявленного времени выпуска, не раньше:- Версия
Должен соответствовать номеру версии, указанному в архиве данных (
django-<version>.tar.gz
). Например: «5.2», «4.1.1» или «4.2rc1».- Активен
Установите значение False до тех пор, пока релиз не будет полностью опубликован (последний шаг).
- LTS (длина волны)
Включить, если релиз является частью ветви LTS.
- Даты
Установите дату выпуска на сегодня. Этот выпуск не будет опубликован, пока не будет включен параметр
is_active
.- Артефакты
Загрузите архивный файл (
django-<version>.tar.gz
), wheel (django-<version>-py3-none-any.whl
), и файлы контрольной суммы (django-<version>.checksum.txt.asc
), созданные ранее.
Проверьте правильность установки релизных пакетов, используя
pip
. Вот один простой метод (он просто проверяет доступность двоичных файлов, их правильную установку и запуск миграции и сервера разработки, но при этом выявляются глупые ошибки): https://code.djangoproject.com/wiki/ReleaseTestNewVersion.Запустите сборку confirm-release на Jenkins для проверки файла(ов) контрольных сумм (например, используйте
4.2rc1
для https://media.djangoproject.com/pgp/Django-4.2rc1.checksum.txt).Загрузите релизные пакеты на PyPI (для предварительных релизов загрузите только файл wheel):
$ twine upload --repository django dist/*
Обновите только что созданный
Release
в разделе администратораdjangoproject.com
и установите флажокis_active
.Разместите свою работу и новый тег:
$ git push $ git push --tags
Сделайте запись в блоге, анонсирующую релиз, прямой трансляцией.
При выходе новой версии (например, 4.1, 4.2) обновите стабильную версию документации по умолчанию, установив флаг
is_default
наTrue
для соответствующего объектаDocumentRelease
в базе данныхdocs.djangoproject.com
(для всех остальных он автоматически установится наFalse
); сделать это можно с помощью администратора сайта.Создайте новые объекты
DocumentRelease
для каждого языка, в котором есть запись для предыдущей версии. Обновите файл djangoproject.com’s robots.docs.txt, скопировав результат, полученный в результате выполнения командыmanage_translations.py robots_txt
в текущей стабильной ветке, из django-docs-translations repository. Например, при выпуске Django 4.2:$ git checkout stable/4.2.x $ git pull $ python manage_translations.py robots_txt
Разместите объявление о выпуске в списке рассылки django-announce и на форуме Django. Это должно содержать ссылку на сообщение в блоге с анонсом.
Если это релиз безопасности, отправьте отдельное письмо на oss-security@lists.openwall.com. Укажите описательную тему, например, «Django» плюс название проблемы из примечаний к релизу (включая CVE ID). В теле сообщения должны содержаться подробности об уязвимости, например, текст сообщения в блоге анонса. Включите ссылку на сообщение в блоге анонса.
После освобождения¶
Вы почти закончили! Все, что теперь осталось сделать, это:
Если это не предварительный релиз, обновите кортеж
VERSION
вdjango/__init__.py
снова, увеличив его до того, каким будет следующий ожидаемый релиз. Например, после выпуска версии 4.1.1 обновитеVERSION
доVERSION = (4, 1, 2, 'alpha', 0)
(example commit).Добавьте релиз в Trac’s versions list, если необходимо (и сделайте его по умолчанию, изменив настройку
default_version
в trac.ini на code.djangoproject.com, если это финальный релиз). Новая версия X.Y должна быть добавлена после выхода альфа-версии, а версия по умолчанию должна быть обновлена после выхода «dot zero».Если бы это был окончательный выпуск:
- Обновите текущую стабильную ветку и удалите предрелизную ветку в Django release process on Track.
- Djangoproject.com обновление загрузки страницы (example PR).
Если это был выпуск безопасности, обновите Архив вопросов безопасности с подробным описанием устраненных проблем.
Если это был предварительный выпуск, то каталоги переводов необходимо обновить:
Создайте новую ветку из недавно выпущенной стабильной ветки:
git checkout stable/A.B.x git checkout -b update-translations-catalog-A.B.x
Убедитесь, что выделенная виртуальная среда выпуска включена, и выполните следующие действия:
$ cd django $ django-admin makemessages -l en --domain=djangojs --domain=django processing locale en
Просмотрите diff перед отправкой и избегайте внесения изменений в файлы
.po
без каких-либо новых переводов (example commit).Сделайте запрос на удаление в соответствующей стабильной ветке и объедините после одобрения.
Перенаправьте обновленные исходные переводы в ветвь
main
(example commit).
Если это был предварительный выпуск
rc
, запросите переводы для предстоящего выпуска в разделе Django Forum - Internationalization category.
Примечания по установке кортежа VERSION¶
Отчетность о версии в Django контролируется кортежем VERSION
в django/__init__.py
. Это кортеж из пяти элементов, элементами которого являются:
- Основная версия.
- Незначительная версия.
- Микро версия.
- Статус – может быть одним из «alpha», «beta», «rc» или «final».
- Номер серии, для пакетов альфа/бета/RC, которые запускаются последовательно (позволяя, например, «beta 1», «beta 2» и т.д.).
Для финального релиза статус всегда «final», а номер серии всегда 0. Номер серии 0 со статусом «альфа» будет представлен как «пре-альфа».
Некоторые примеры:
(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»