xref: /PHP-8.4/docs/release-process.md (revision 13f04116)
1# PHP Release Process
2
3A release manager's role includes making packaged source code from the canonical
4repository available according to the release schedule.
5
6The release schedule for each version is published on the
7[PHP wiki](https://wiki.php.net):
8
9- [PHP 8.3](https://wiki.php.net/todo/php83)
10- [PHP 8.2](https://wiki.php.net/todo/php82)
11- [PHP 8.1](https://wiki.php.net/todo/php81)
12
13The PHP project publishes builds every two weeks.
14
15We publish [general availability][] (GA) releases for major and minor versions of
16PHP on the fourth Thursday of November each year. Following the GA release, we
17publish patch-level releases every four weeks, with at least one release
18candidate (RC) published two weeks before each patch-level release.
19
20Each major and minor version undergoes a 24-week pre-release cycle before GA
21release. The pre-release cycle begins on the second Thursday of June with the
22first alpha release of the new major/minor version. The pre-release cycle
23consists of at least:
24
25- 3 alpha releases
26- 3 beta releases
27- 6 release candidates
28
29Feature freeze for the next major/minor occurs with the first beta release.
30
31We refer to alpha, beta, and RC as *non-stable releases*, while GA are *stable*.
32
33The process of making packaged source available and announcing availability is
34explained in detail below. The process differs slightly for non-stable and
35stable releases.
36
37New release managers should review [New release manager
38checklist](#new-release-manager-checklist) at the end of this document. This
39section  explains the procedures for getting ready to begin work on managing PHP
40releases.
41
42
43## General notes and tips
44
451. Do not release on Fridays, Saturdays, or Sundays as this gives poor lead
46   time for downstream consumers adhering to a typical work week.
47
48   Our general procedure is to release on Thursdays, whenever possible.
49
502. Package two days before a release.
51
52   If the release is to be on Thursday, package on Tuesday. Think about
53   timezones as well.
54
553. Ensure that the relevant tests on CI are green.
56
57   - https://cirrus-ci.com/github/php/php-src
58   - https://github.com/php/php-src/actions
59
60   > �� **Tip** \
61   > We recommend checking the build status a couple of days before packaging day
62   > to allow enough time to investigate failures, communicate with the authors,
63   > and commit any fixes.
64   >
65   > Check the CI status for your branch periodically and resolve the failures
66   > ASAP.
67   >
68   > See more in https://wiki.php.net/rfc/travis_ci.
69
704. Follow all steps to the letter.
71
72   > �� **Tip** \
73   > When you are unsure about anything, ask a previous RM before proceeding.
74   > Ideally, make sure a previous RM is available to answer questions during
75   > the first few releases of your version. For the steps related to the
76   > `web-php`, `web-qa`, and `web-php-distributions` repositories, try to have
77   > someone from the webmaster team on hand.
78
795. Verify the tags to be extra sure everything was tagged properly.
80
816. There is a PHP release Docker image https://github.com/sgolemon/php-release
82   with forks available to help with releases.
83
847. Communicate with release managers via release-managers@php.net.
85
868. References to repositories in this document refer to the canonical source
87   located at https://github.com/php.
88
899. It might be helpful to name your remote repositories something other than
90   "origin" to avoid accidentally pushing changes to "origin" with [muscle
91   memory][].
92
9310. It might also be helpful to set up conditional includes in your global
94    `~/.gitconfig` to set the proper `user.name`, `user.email`, and
95    `user.signingKey` values to use with your local PHP repositories. See
96    [Conditional Includes For Git Config][] for more information.
97
98
99## Packaging a non-stable release (alpha/beta/RC)
100
101All releases during the pre-release cycle (alpha/beta/RC) leading up to the GA
102release for a version are *non-stable* releases. Following the GA release, all
103RCs are *non-stable* releases.
104
105All non-stable releases follow a similar pattern, though pre-GA releases have
106slightly different steps. We'll call attention where the steps differ.
107
1081. Check that CI is passing (see above).
109
1102. Run `./scripts/dev/credits` in php-src and commit the changes to the credits
111   files in `ext/standard`.
112
113   > �� **Hint** \
114   > It's rare this script will make any changes, so if you run `git diff`
115   > and do not see anything, there's no need to panic. That means there are no
116   > changes to the credits files.
117
1183. Check out the *release branch* for this release from the *version branch*.
119
120   > �� **Non-stable version branches: pre-GA** \
121   > There is no *version branch* for alpha or beta releases. Instead, treat the
122   > main branch as the version branch. You will create a local-only release
123   > branch from the main branch. Do not push it!
124   >
125   > ```shell
126   > git checkout -b php-X.Y.0alpha1-local-release-branch upstream/master
127   > ```
128   >
129   > During the first RC release, you will create (and push!) the version
130   > branch for the pre-GA release, e.g., `PHP-8.2`. See
131   > "[Forking a new version branch](#forking-a-new-version-branch)" below.
132   > From this point forward, all pre-GA release branches will be created from
133   > this version branch. Again, these release branches are local-only. Do not
134   > push them!
135   >
136   > ```shell
137   > git checkout -b php-X.Y.0beta2-local-release-branch upstream/PHP-X.Y
138   > ```
139
140   > �� **Non-stable version branches: post-GA** \
141   > After GA, you will create (and push) a new *patch-level version branch*
142   > along with each non-stable release. For example, if you are building a
143   > release for PHP 8.2.8 RC1, you will create the `PHP-8.2.8` patch-level
144   > version branch from the `PHP-8.2` version branch.
145   >
146   > ```shell
147   > git checkout -b PHP-X.Y.Z upstream/PHP-X.Y
148   > git push upstream PHP-X.Y.Z
149   > ```
150   >
151   > We will use the patch-level version branch to commit any critical bug or
152   > security fixes before this version's GA.
153   >
154   > Then, from the patch-level version branch, you will create another
155   > local-only release branch. Do not push this one!
156   >
157   > ```shell
158   > git checkout -b php-X.Y.ZRC1-local-release-branch upstream/PHP-X.Y.Z
159   > ```
160
1614. Using your local-only release branch, bump the version numbers in
162   `main/php_version.h`, `Zend/zend.h`, `configure.ac`, and possibly
163   `NEWS`.
164
165   For examples, see [Update versions for PHP 8.1.0beta3][] (for a pre-GA
166   example) or [Update versions for PHP 8.1.6RC1][] along with
167   [Update NEWS for PHP 8.1.6RC1][] (for a post-GA example).
168
169   > ⚠️ **Important** \
170   > Do not use abbreviations for alpha or beta. Do not use dashes as
171   > separators.
172   >
173   > Do this:
174   >
175   > ```c
176   > #define PHP_VERSION "7.4.22RC1"
177   > ```
178   >
179   > Not this:
180   >
181   > ```c
182   > #define PHP_VERSION "7.4.22-RC1"
183   > ```
184
185   > �� **Note** \
186   > We update `Zend/zend.h` only when preparing RC and GA releases. We do not
187   > update `ZEND_VERSION` for alpha or beta releases.
188
189   > �� **API version bump for pre-GA** \
190   > When releasing the *first release candidate* of a pre-GA release, you must
191   > also bump the API version numbers in `Zend/zend_extensions.h`,
192   > `Zend/zend_modules.h`, and `main/php.h`. See [Prepare for PHP 8.1.0RC1][],
193   > for example.
194   >
195   > The API versions between the alpha, beta, and X.Y.0RCn releases may remain
196   > the same, or be bumped as little as possible because PHP extensions need to
197   > be rebuilt with each bump.
198   >
199   > Do *not* bump the API versions after RC1.
200
2015. Compile and run `make test`, with and without ZTS (Zend Thread Safety), using
202   the correct Bison and re2c versions, e.g., for PHP 7.4, Bison 3.0.0 and re2c
203   0.13.4 are required, as a minimum.
204
205   For example:
206
207   ```shell
208   # With ZTS
209   make distclean || \
210   ./buildconf --force \
211       && ./configure --enable-zts --disable-all --enable-debug --enable-opcache --enable-opcache-jit \
212       && make -j$(nproc) \
213       && make test TEST_PHP_ARGS="-q -j$(nproc)" \
214       || ./sapi/cli/php -v
215
216   # Without ZTS
217   make distclean || \
218   ./buildconf --force \
219       && ./configure --disable-all --enable-debug --enable-opcache --enable-opcache-jit \
220       && make -j$(nproc) \
221       && make test TEST_PHP_ARGS="-q -j$(nproc)" \
222       || ./sapi/cli/php -v
223   ```
224
2256. After each build, check the output of `./sapi/cli/php -v` to ensure the
226   versions match the release.
227
2287. If all is correct, commit the changes to your local-only release branch.
229
230   ```shell
231   git add -p
232   git commit --gpg-sign=YOURKEYID -m "Update versions for PHP X.Y.ZRCn"
233   ```
234
2358. Tag your local-only release branch with the release version.
236
237   ```shell
238   git tag -s -u YOURKEYID php-X.Y.ZRCn -m "Tag for php-X.Y.ZRCn"
239   ```
240
2419. �� **For pre-GA releases only,** switch back to the `master` (for alphas and betas),
242   or `PHP-X.Y` (for RCs), and update a `NEWS` for the new version. See
243   [Update NEWS for PHP 8.2.0 alpha2][] and [Update NEWS for PHP 8.2.0RC6][] for a real example.
244
245   Commit the changes to the `master` (or `PHP-X.Y`) branch.
246
247   ```shell
248   git add -p
249   git commit --gpg-sign=YOURKEYID -m "[ci skip] Update NEWS for PHP X.Y.Z alpha2"
250   ```
251
252   �� **For post-GA releases only,** switch back to the *version branch* for
253   your release (e.g., `PHP-8.2`) and bump the version numbers in
254   `main/php_version.h`, `Zend/zend.h`, `configure.ac` and `NEWS`. This prepares
255   the version branch for the next version.
256
257   For example, if the RC is `8.2.1RC1` then the version numbers in the version
258   branch should be bumped to `8.2.2-dev`. We do this regardless of whether we
259   build a new RC to make sure `version_compare()` works correctly. See
260   [Bump for 8.1.8-dev][] for a real example.
261
262   Commit the changes to the version branch.
263
264   ```shell
265   git add -p
266   git commit --gpg-sign=YOURKEYID -m "PHP-X.Y is now for PHP X.Y.Z-dev"
267   ```
268
269   > �� **Tip** \
270   > Version branches (e.g. `PHP-8.1`) will *always* have version numbers in
271   > `main/php_version.h`, `Zend/zend.h`, and `configure.ac` that end in `-dev`.
272   > Patch-level version branches (e.g. `PHP-8.1.7`) will also *always* have
273   > version numbers that end in `-dev` in these files. The main branch (i.e.
274   > `master`) will *always* have version numbers that end in `-dev` in these
275   > files.
276   >
277   > Only release tags should have version numbers in these files that do not
278   > end in `-dev` (e.g., `8.1.7`, `8.1.7RC1`, `8.2.0alpha1`, etc.).
279
28010. Push the changes to the `php-src`.
281
282    ```shell
283    git push upstream php-X.Y.ZRCn # tag name
284    git push upstream PHP-X.Y.Z    # patch-level version branch (post-GA only)
285    git push upstream PHP-X.Y      # version branch
286    ```
287
288    > �� **Attention** \
289    > Do not push with `--tags`, as this will push all local tags, including
290    > tags you might not wish to push.
291    >
292    > Local-only release branches should not be pushed!
293
29411. Run the following using the release tag to export the tree, create the
295    `configure` script, and build and compress three tarballs (`.tar.gz`,
296    `.tar.bz2` and `.tar.xz`).
297
298    ```shell
299    ./scripts/dev/makedist php-X.Y.ZRCn
300    ```
301
30212. Run the following using the release tag and your GPG key ID to sign the
303    tarballs and save the signatures to `php-X.Y.ZRCn.manifest`, which you can
304    upload to GitHub and include in the announcement emails.
305
306    ```shell
307    ./scripts/dev/gen_verify_stub X.Y.ZRCn YOURKEYID > php-X.Y.ZRCn.manifest
308    ```
309
31013. If you have the [GitHub command line tool][] installed, run the following to
311    create a public Gist for the manifest file:
312
313    ```shell
314    gh gist create --public php-X.Y.ZRCn.manifest
315    ```
316
317    Or you may go to https://gist.github.com to create it manually.
318
31914. Copy the tarballs (using scp, rsync, etc.) to your `public_html/` folder on
320    downloads.php.net.
321
322    ```shell
323    scp php-X.Y.ZRCn.tar.* downloads.php.net:~/public_html/
324    ```
325
326    > �� **Hint** \
327    > If you do not have a `public_html` directory, create it and set its
328    > permissions to `0755`.
329
33015. Now the tarballs and signatures may be found at
331    `https://downloads.php.net/~yourname/`, e.g. https://downloads.php.net/~derick/.
332
33316. Once the release is tagged, contact the release-managers@php.net distribution
334    list so that Windows binaries can be created. Once those are made, they may
335    be found at https://windows.php.net/qa/.
336
337    Here is an example "ready for builds" message to release-managers@php.net:
338
339    ```text
340    Subject: PHP 8.1.6RC1 ready for builds
341
342    Hi, all!
343
344    Tag: php-8.1.6RC1
345    Tarballs: https://downloads.php.net/~ramsey/
346    Manifest: https://gist.github.com/ramsey/5d73f0717effb6d8d17699381361e4b1
347
348    Cheers,
349    Ben
350
351    << PASTE FULL MANIFEST CONTENTS HERE >>
352    ```
353
354
355## Announcing a non-stable release (alpha/beta/RC)
356
3571. Switch to your local clone of the `web-qa` repository and update the
358   information in the `$QA_RELEASES` array in `include/release-qa.php`.
359
360   Follow the documentation in the file for editing the QA release information.
361   See also [Announce 8.1.0RC3][] and [8.1.6RC1][] for examples.
362
363   Add, commit, and push your changes, when finished.
364
365   ```shell
366   git add -p
367   git commit --gpg-sign=YOURKEYID -m "Announce PHP X.Y.ZRCn"
368   git push upstream master
369   ```
370
3712. �� **For pre-GA releases only,** add a short notice to `web-php` stating
372   there is a new release, and highlight the major changes (e.g., security
373   fixes).
374
375   To help produce the files for this, use the `bin/createNewsEntry` tool. When
376   you run it, it will ask several questions (see below). For pre-GA non-stable
377   releases, use only the "frontpage" category.
378
379   ```shell
380   cd /path/to/repos/php/web-php
381   ./bin/createNewsEntry
382   # Please type in the title: PHP X.Y.0 Alpha n available for testing
383   # Categories:
384   #     0: PHP.net frontpage news   [frontpage]
385   #     1: New PHP release          [releases]
386   #     2: Conference announcement  [conferences]
387   #     3: Call for Papers          [cfp]
388   # Please select appropriate categories, separated with space: 0
389   # Will a picture be accompanying this entry? no
390   # And at last; paste/write your news item here.
391   # To end it, hit <enter>.<enter>
392   #
393   #   [[ Here you will paste the full HTML of the post. ]]
394   # .
395   #
396   git add -p
397   git add archive/entries/*.xml
398   git commit --gpg-sign=YOURKEYID -m "Announce PHP X.Y.0RCn"
399   git push upstream master
400   ```
401
402   Each news entry for pre-GA releases will be similar, though we change the
403   text slightly to indicate progression through the pre-release cycle. For
404   example, here are all the news posts for the pre-GA releases of PHP 8.1.0:
405
406   * [Announce 8.1.0alpha1](https://github.com/php/web-php/commit/57b9675c8d8550493289fa1fba77427c93cdd472)
407   * [Announce 8.1.0alpha2](https://github.com/php/web-php/commit/cec044fc0763f5cfa77d0e79479f8b6279023570)
408   * [Announce 8.1.0alpha3](https://github.com/php/web-php/commit/5c480765f444a3fddfd575e01fe0be3fcfdde05b)
409   * [Announce 8.1.0beta1](https://github.com/php/web-php/commit/40840e3c3f89d6dd95baa4b8cdf22d6f206f86c2)
410   * [Announce 8.1.0beta2](https://github.com/php/web-php/commit/7bf6acdadd4940bd9db711bf3f9d5a4054dc0722)
411   * [Announce 8.1.0beta3](https://github.com/php/web-php/commit/38c8a872700fb0c2ebde49e2eae3374257ba6d08)
412   * [Announce 8.1.0RC1](https://github.com/php/web-php/commit/6e4bf3d0228ce113728d5f1a769ed42e0d63ca10)
413   * [Announce 8.1.0RC2](https://github.com/php/web-php/commit/1ae95f4b686a5d614a94a664a7466ee0e5cd21eb)
414   * [Announce 8.1.0RC3](https://github.com/php/web-php/commit/3091246d77a3f445fcc593587597d0abcab8c373)
415   * [Announce 8.1.0RC4](https://github.com/php/web-php/commit/fbaeb9403f4e2856115889946d3f63751e183c7b)
416   * [Announce 8.1.0RC5](https://github.com/php/web-php/commit/46473ccccfb5f7fedc3f169c55fb7c22a596b55d)
417   * [Announce 8.1.0RC6](https://github.com/php/web-php/commit/cacaef9c41352b5dbf3fbbf44702cc6c0cbfb478)
418
419   > ⚠️ **Important** \
420   > In your announcement news entry, be sure to include the following text or
421   > text similar to the following:
422   >
423   > > Please DO NOT use this version in production, it is an early test version.
424
425   > �� **Note** \
426   > When a version is in its post-GA phase, we do not post news entries for
427   > non-stable releases.
428
4293. Wait for the web and qa sites to update with the new information before
430   sending announcements. This could take up to an hour.
431
4324. Send *separate* announcement emails to:
433
434   * `internals@lists.php.net`
435   * `php-general@lists.php.net`
436   * `php-qa@lists.php.net`
437
438   In the announcement message, point out the location of the release and the
439   possible release date of either the next RC or the final release. Also
440   include the manifest generated by `gen_verify_stub` when you packaged the
441   build.
442
443   Here are a few examples of non-stable release announcement emails:
444
445   * [PHP 8.1.0alpha1 is available for testing](https://news-web.php.net/php.qa/69043)
446   * [PHP 8.1.0beta3 available for testing](https://news-web.php.net/php.qa/69079)
447   * [PHP 8.1.0RC6 available for testing](https://news-web.php.net/php.qa/69117)
448   * [PHP 8.1.7RC1 Ready for testing](https://news-web.php.net/php.qa/69163)
449
450   > �� **Send separate emails!** \
451   > Do *not* send a single email message with all addresses in the `To`, `Cc`,
452   > or `Bcc` headers. If a user replies to one of these messages, we do not
453   > want their email client to automatically send the reply to each list, as
454   > often occurs.
455
456   > �� **Hint** \
457   > We send emails to the followers of these mailing lists to notify them of
458   > new releases, so they can make sure their projects keep working and can
459   > report any potential bugs that should be fixed before the upcoming GA
460   > release.
461
4625. �� **For pre-GA *RCs* only,** coordinate with the social media team (i.e.,
463   Derick) to post a tweet with the RC release announcement and link to the news
464   entry on php.net. ([@official_php](https://twitter.com/official_php))
465
466
467## Packaging a stable release
468
4691. Check out the *patch-level version branch* for the release
470   (e.g., `PHP-8.1.7`).
471
472   > �� **Hint** \
473   > You should have created this branch when packaging the non-stable release
474   > candidate for this version. If it is for a PHP-X.Y.0 version, then just
475   > create and push this branch.
476
4772. If a CVE commit needs to be merged to the release, have it committed to
478   the base branches and [merged upwards as usual][] (e.g. commit the CVE fix
479   to 7.2, merge to 7.3, 7.4, etc.). Then, you can cherry-pick it into the
480   patch-level version branch for this release.
481
482   Commit these changes and push the patch-level version branch. Ensure
483   that CI is still passing (see above).
484
485   > �� **Tip** \
486   > Don't forget to update `NEWS` manually in an extra commit to the
487   > patch-level version branch.
488
4893. Run the `./scripts/dev/credits` script in the patch-level version branch,
490   and commit the changes in the credits files in `ext/standard`.
491
492   > �� **Note** \
493   > It's very rare this will make changes at this point, but we run it here
494   > in case the credits changed as a result of a bug fix that was
495   > cherry-picked into this branch.
496
4974. Create a local-only release branch for this release from the *patch-level
498   version branch*.
499
500   ```shell
501   git checkout -b php-X.Y.Z-local-release-branch upstream/PHP-X.Y.Z
502   ```
503
5045. Using your local-only release branch, bump the version numbers in
505   `main/php_version.h`, `Zend/zend.h`, `configure.ac`, and possibly
506   `NEWS`.
507
508   For example, if you're releasing a stable version for PHP 8.1.8, then all
509   the version numbers in the patch-level version branch should be
510   `8.1.8-dev`. In your local-only release branch, you will change them all to
511   `8.1.8`.
512
513   See [Update versions for PHP 8.1.7][] and [Update NEWS for PHP 8.1.7][] for
514   an example.
515
5166. Compile and run `make test`, with and without ZTS (Zend Thread Safety), using
517   the correct Bison and re2c versions, e.g., for PHP 7.4, Bison 3.0.0 and re2c
518   0.13.4 are required, as a minimum.
519
520   For example:
521
522   ```shell
523   # With ZTS
524   make distclean || \
525   ./buildconf --force \
526       && ./configure --enable-zts --disable-all --enable-debug --enable-opcache --enable-opcache-jit \
527       && make -j$(nproc) \
528       && make test TEST_PHP_ARGS="-q -j$(nproc)" \
529       || ./sapi/cli/php -v
530
531   # Without ZTS
532   make distclean || \
533   ./buildconf --force \
534       && ./configure --disable-all --enable-debug --enable-opcache --enable-opcache-jit \
535       && make -j$(nproc) \
536       && make test TEST_PHP_ARGS="-q -j$(nproc)" \
537       || ./sapi/cli/php -v
538   ```
539
5407. After each build, check the output of `./sapi/cli/php -v` to ensure the
541   versions match the release.
542
5438. If all is correct, commit the changes to your local-only release branch.
544
545   ```shell
546   git add -p
547   git commit --gpg-sign=YOURKEYID -m "Update versions for PHP X.Y.Z"
548   ```
549
5509. Tag your local-only release branch with the release version and push the tag.
551
552   ```shell
553   git tag -s -u YOURKEYID php-X.Y.Z -m "Tag for php-X.Y.Z"
554   git push upstream php-X.Y.Z
555   ```
556
55710. Run the following using the release tag to export the tree, create the
558    `configure` script, and build and compress three tarballs (`.tar.gz`,
559    `.tar.bz2` and `.tar.xz`).
560
561    ```shell
562    ./scripts/dev/makedist php-X.Y.Z
563    ```
564
565    > �� **Hint** \
566    > Check if the PEAR files are updated (Phar).
567
568    > �� **Tip** \
569    > On some systems the behavior of GNU tar can default to produce POSIX
570    > compliant archives with PAX headers. As not every application is
571    > compatible with that format, creation of archives with PAX headers should
572    > be avoided. When packaging on such a system, the GNU tar can be influenced
573    > by defining the environment variable `TAR_OPTIONS='--format=gnu'`.
574
57511. Run the following using the release tag and your GPG key ID to sign the
576    tarballs and save the signatures to `php-X.Y.Z.manifest`, which you can
577    upload to GitHub and include in the announcement emails.
578
579    ```shell
580    ./scripts/dev/gen_verify_stub X.Y.Z YOURKEYID > php-X.Y.Z.manifest
581    ```
582
58312. If you have the [GitHub command line tool][] installed, run the following to
584    create a public Gist for the manifest file:
585
586    ```shell
587    gh gist create --public php-X.Y.Z.manifest
588    ```
589
590    Or you may go to https://gist.github.com to create it manually.
591
59213. Switch to your local clone of the `web-php-distributions` repository and
593    copy the tarballs and signature files into the repository. Add, commit, and
594    push them.
595
596    ```shell
597    cd /path/to/repos/php/web-php-distributions
598    mv /path/to/repos/php/php-src/php-X.Y.Z.tar.* .
599    git add php-X.Y.Z.tar.*
600    git commit --gpg-sign=YOURKEYID -m "Add tarballs for php-X.Y.Z"
601    git push upstream master
602    ```
603
60414. Switch to your local clone of the `web-php` repository and update the
605    `web-php-distributions` submodule.
606
607    ```shell
608    cd /path/to/repos/php/web-php
609    git pull --rebase upstream master
610    git submodule init
611    git submodule update
612    cd distributions
613    git fetch --all
614    git pull --rebase upstream master
615    cd ..
616    git commit distributions -m "X.Y.Z tarballs"
617    git push upstream master
618    ```
619
620    > �� **Hint** \
621    > This fetches the last commit ID from `web-php-distributions` and pins the
622    > "distributions" submodule in `web-php` to this commit ID.
623    >
624    > When the website syncs, which should happen within an hour, the tarballs
625    > will be available from `https://www.php.net/distributions/php-X.Y.Z.tar.gz`,
626    > etc.
627
62815. Once the release is tagged, contact the release-managers@php.net distribution
629    list so that Windows binaries can be created. Once those are made, they may
630    be found at https://windows.php.net/qa/.
631
632    > ⚠️ **Important** \
633    > Do *not* send this announcement to any public lists.
634
635    Here is an example "ready for builds" message to release-managers@php.net:
636
637    ```text
638    Subject: PHP 8.1.6 ready for builds
639
640    Hi, all!
641
642    Tag: php-8.1.6
643    Tarballs: web-php-distributions
644    Manifest: https://gist.github.com/ramsey/432fcf8afcbfb1f1de6c3ab47d82e366
645
646    Cheers,
647    Ben
648
649    << PASTE FULL MANIFEST CONTENTS HERE >>
650    ```
651
652
653## Announcing a stable release
654
6551. This steps applies only for releases after PHP-X.Y.0.
656
657   Switch to your local clone of `web-php` and add the information for the
658   previous release to `include/releases.inc`.
659
660   For example, if you are preparing to announce version 8.2.2, then the
661   previous release is 8.2.1, so you will add the information for 8.2.1 to this
662   file. Most of the time, you can do this using the `bin/bumpRelease` tool.
663
664   ```shell
665   ./bin/bumpRelease 8 2
666   ```
667
668   The first number is the major version, and the second number is the minor
669   version. In this example, we're bumping the release information for version
670   8.2. There is no need to provide the patch level.
671
672   > �� **Tip** \
673   > If this fails for any reason, you can manually copy the information
674   > for the previous release from `include/version.inc` into
675   > `include/releases.inc`.
676
6773. Update the version information for the new release in `include/version.inc`.
678
679   Find the part of the `$data` array that is related to your version (e.g.,
680   `$data['8.2']` for 8.2.x releases) or create a new section if releasing
681   PHP-X.Y.0 version, and make the following edits / additions:
682
683   * Set `version` to the full version number (e.g. '8.2.1')
684   * Set `date` to the release date in `j M Y` format (e.g. '5 Jan 2021')
685   * Update the `tags` array to include `'security'` if this is a security release
686   * Set the `sha256` array with the hashes for each of the release tarballs
687
6885. Create the release file and news entry for the new version.
689
690   ```shell
691   ./bin/createReleaseEntry -v X.Y.Z -r # --security for security releases
692   ```
693
694   This will create a release file (i.e., `releases/X_Y_Z.php`) and a news entry
695   file (i.e., `archive/entries/YYYY-MM-DD-n.xml`), while also updating
696   `archive/archive.xml`.
697
698   Within these files, it will generate standard messages for the new version.
699   You may edit the generated files to expand on the base message, if needed.
700
701   The edits are necessary for PHP-X.Y.0 version where the format is different.
702   See for example [PHP-8.2 announcement](https://github.com/php/web-php/commit/c966868202caafa880213055f4e3e97c0483119b)
703
7047. Update the ChangeLog file for the given major version (e.g., `ChangeLog-8.php`).
705
706   If PHP-X.Y.0 is released, modify the `ChangeLog-X.php` (where `X` is the major
707   version) file manually first. The `$MINOR_VERSIONS` field needs to be extended
708   with the new version and initial anchor (e.g. `<a id="PHP_8_4"></a>` if added
709   for PHP 8.4) added above the first anchor of the previous version.
710
711   ```shell
712   ./bin/news2html 'https://github.com/php/php-src/raw/php-X.Y.Z/NEWS' 'X.Y.Z' 'ChangeLog-X.php'
713   ```
714
7159. Review all the changes in `web-php`, commit, and push them.
716
717   ```shell
718   git add -p
719   git add archive/entries/*.xml releases/*.php
720   git commit --gpg-sign=YOURKEYID -m "Announce PHP X.Y.Z"
721   git push upstream master
722   ```
723
724   See [Announce PHP 8.1.6][] for an example commit.
725
72610. Switch to your local clone of the `web-qa` repository and update the
727   information in the `$QA_RELEASES` array in `include/release-qa.php`.
728
729   The array probably contains information about the RC released two weeks ago
730   in preparation for the current release. Since the current release is now GA,
731   it's time to remove the RC build from the QA website.
732
733   It is sufficient to set the `number` property for the release to `0` to
734   stop displaying the RC build on the QA website. You may also remove the
735   sha256 hashes for the RC tarballs, but it's not necessary. For an example,
736   see [PHP 8.1.6 released][].
737
738   Add, commit, and push your changes, when finished.
739
740   ```shell
741   git add -p
742   git commit --gpg-sign=YOURKEYID -m "PHP X.Y.Z released"
743   git push upstream master
744   ```
745
74611. �� **Before sending announcement emails, check to make sure the websites have
747   synced.**
748
749   * Make sure the tarballs are available from, e.g.,
750     `https://www.php.net/distributions/php-X.Y.Z.tar.gz`
751   * Check the "downloads" page to make sure the new version appears:
752     https://www.php.net/downloads
753   * Does the news entry show up on the home page? https://www.php.net
754   * Do the updates to the ChangeLog appear?
755     e.g., https://www.php.net/ChangeLog-8.php
756   * Is there a release page for the new version?
757     e.g., `https://www.php.net/releases/X_Y_Z.php`
758   * Does the RC for this version still appear on the QA home page?
759     https://qa.php.net
760
761   Keep in mind it may take up to an hour for the websites to sync.
762
76311. Please note down the sha256 and the PGP signature (.asc). These *must* be
764   included in the release mail.
765
76612. Send *separate* announcement emails to:
767
768   * `php-announce@lists.php.net`
769   * `php-general@lists.php.net`
770   * `internals@lists.php.net`
771
772   Release announcement emails must include the manifest generated when
773   packaging the build, along with links to the sources, Windows binaries, and
774   changelog. Here are a few examples of stable release announcement emails:
775
776   * [PHP 8.1.0 Released](https://news-web.php.net/php.announce/321)
777   * [PHP 8.1.3 Released](https://news-web.php.net/php.announce/325)
778   * [PHP 8.1.6 Released](https://news-web.php.net/php.announce/331)
779
780   > ⚠️ **Important** \
781   > For standard patch-level releases, we will note "This is a bugfix release."
782   > If it is a security release, we must note "This is a security release."
783
784   > �� **Send separate emails!** \
785   > Do *not* send a single email message with all addresses in the `To`, `Cc`,
786   > or `Bcc` headers. If a user replies to one of these messages, we do not
787   > want their email client to automatically send the reply to each list, as
788   > often occurs.
789
79013. Coordinate with the social media team (i.e., Derick) to
791    [create a PR request](https://github.com/derickr/toot-together/blob/main/toots/README.md)
792    for posting the release announcement to Mastodon. Posts need to be
793    approved.
794
795## Re-releasing the same version or a patch-level (i.e., `-plN`)
796
797While unlikely, there may be times we need to re-release the same version. This
798might happen if the tarballs have a corrupted file, for example.
799
800Should this occur *before* announcing the release, you may choose to delete the
801tag and go through the full packaging process again, as described above.
802
803> �� **Hint** \
804> This is one of the reasons we package releases two days before announcing
805> them.
806
807If this happens *after* announcing the release, you may choose to tag, package,
808and release a patch-level (i.e., *pl*) release. If it is not critical and/or
809affects a very limited subset of users, then you may choose to wait until the
810next release.
811
812If you choose to create a patch-level release, follow these steps:
813
8141. Commit the new binaries to `web-php-distributions`
815
8162. Update $data['X.Y'] in `web-php:/include/version.inc`
817   (X.Y=major.minor release, e.g. '8.0'):
818
819    * `version` to the full version number (e.g. '8.0.1-pl1')
820    * `date` to the release date in `j M Y` format (e.g. '9 Jan 2021')
821    * `tags` array should include `security` if this is a security release
822    * `sha256` array and sub-elements for all SHA256 sums
823
8243. Add a short notice to `web-php` stating that there is a new release, and
825   highlight the major important things (security fixes) and when it is
826   important to upgrade.
827
828    * Call `php bin/createReleaseEntry -v <version> [ --security ]` in your
829      local web-php checkout.
830
8314. Commit all the changes (`include/version.inc`, `archive/archive.xml`,
832   `archive/entries/YYYY-MM-DD-N.xml`).
833
8345. Wait an hour or two, then send a mail to php-announce@lists.php.net,
835   php-general@lists.php.net and internals@lists.php.net with a text similar to
836   the news entry.
837
838   Please make sure that the mail to php-announce@ is its own completely
839   separate email. This is to make sure that replies to the announcement on
840   php-general@ or internals@ will not accidentally hit the php-announce@
841   mailinglist.
842
843
844## Feature freeze
845
846A major/minor version [feature freeze][] occurs with the first beta release.
847Specifically, it occurs when the first beta release is packaged, which means the
848feature freeze occurs two days before the first beta release.
849
850The feature freeze for `php-src` means that we will not accept any new features
851after the date of the feature freeze. For any RFCs to be included in the new
852version, they should be discussed and have the voting polls closed no later than
853the feature freeze date. However, this does not mean the new feature must have a
854complete implementation by this date.
855
856Following the feature freeze, the focus of work for the new version will be on
857fixing bugs, writing tests, and completing/polishing all accepted features.
858
859As a courtesy to the community, the release managers should remind others about
860the upcoming feature freeze by posting reminders to internals@lists.php.net at
8614-weeks, 3-weeks, 2-weeks, and 1-week prior to the feature freeze. This is a
862recommendation and the intervals may vary based on work load.
863
864
865## Forking a new version branch
866
867When the new version has reached the first RC, it is time to create a new
868version branch. This frees up the main branch (i.e., `master`) for any new
869feature development that cannot go into the new version.
870
8711. One week prior to tagging `X.Y.0RC1`, warn internals@ that your version's
872   branch is about to be created. Be specific about when the branch creation
873   will occur. For example: https://news-web.php.net/php.internals/99864
874
8752. Just prior to tagging `X.Y.0RC1`, create the new version branch locally,
876   i.e. `PHP-X.Y`.
877
8783. Add a commit on the main branch (i.e., `master`) after the branch point.
879
880   This commit should:
881
882   * clear the `NEWS`, `UPGRADING`, and `UPGRADING.INTERNALS` files;
883   * update the version numbers in `configure.ac`, `main/php_version.h`,
884     `Zend/zend.h`, and `win32/build/confutils.js`;
885   * update the API version numbers in `Zend/zend_extensions.h`,
886     `Zend/zend_modules.h`, and `main/php.h`; and
887   * add the new branch to the list in `CONTRIBUTING.md`.
888
889   See [Prepare for PHP 8.2][] and [Prepare for PHP 8.2 (bis)][] for an example
890   of what this commit should include.
891
8924. Push the new version branch and the changes to the `master` branch, with an
893   appropriate commit message (e.g., "master is now for PHP 8.3.0-dev").
894
8955. Immediately notify internals@ of the new branch and advise on the new merging
896   order. For example: https://news-web.php.net/php.internals/99903
897
8986. Update `web-php:git.php` and https://wiki.php.net/vcs/gitworkflow to reflect
899   the new branch.
900
901   For example:
902
903   * [Add PHP-8.1 to the Git steps page][]
904   * [Changes to the wiki][]
905
906> �� **Hint** \
907> We create the new version branch at the first release candidate rather than at
908> feature freeze to allow a period of time where the focus is on making the new
909> version ready for RC and GA. During this time, the main branch is *only* for
910> minor improvements and bug fixes. All major improvements and new features must
911> wait.
912
913
914## Preparing for the initial stable version (PHP X.Y.0)
915
9161. When you release the first pre-GA RC, remind the documentation team
917   (phpdoc@lists.php.net) to write the [migration guide][]. Make sure the guide
918   is available before releasing the initial stable version, since you should
919   link to it in the release announcements.
920
9212. Timely get used to the differences in preparing and announcing a stable
922   release.
923
9243. Before releasing X.Y.0, merge the `NEWS` entries of the pre-releases, so that
925   there is only a single section about PHP X.Y.0, instead of individual
926   sections for each pre-release.
927
928   All the changes that are already present in the previous version NEWS should be
929   removed. It means all bug fixes that went to the previous version as well should
930   have their entries removed. It is possible to use `grep` to compare the changes.
931   For example if `82/NEWS` is NEWS for PHP 8.2 and `83/NEWS` is NEWS file for PHP 8.3,
932   then following command will show changes present in both files:
933
934   ```sh
935   grep -Fxf 82/NEWS 83/NEWS
936   ```
937
938
9395. On the announcement day for the initial stable version (or shortly before),
940   update the `Expires` field in the <https://www.php.net/.well-known/security.txt>
941   file. The `Expires` field should be set to the expected date of the next X.Y.0
942   release (following the one currently being prepared), which is usually the
943   fourth Thursday of November in the next year.
944
945   Following the recommendation of [RFC 9116](https://www.rfc-editor.org/rfc/rfc9116),
946   we maintain an `Expires` time of about a year for our security policies. This
947   provides security researchers with confidence they are using our most
948   up-to-date reporting policies.
949
950   The `security.txt` file is located in the [web-php repository](https://github.com/php/web-php)
951   under the `.well-known/` directory. We may make changes to this file at other
952   times, as needed, but we will always advance the `Expires` timestamp on a
953   yearly cadence, coinciding with our X.Y.0 releases.
954
955   Please see the instructions for
956   [making changes to security.txt][security-txt].
957
958
959## Prime the selection of release managers for the next version
960
961About three months prior to the scheduled release of the first alpha release of
962the next  minor or major version (around March 1st or shortly thereafter), the
963release managers for the latest version branch should issue a call for
964volunteers to begin the selection process for the next release managers.
965
9661. Issue the call for volunteers on internals@lists.php.net on or around March
967   1st. See, for example: https://news-web.php.net/php.internals/113334
968
969   There is no rule for how long the call for volunteers must remain open. We
970   should aim to select the release managers by early April, so announcing the
971   call in early March gives people about a month to decide whether they wish to
972   volunteer.
973
9742. There should be two or more volunteers. Typically, one should be a veteran
975   release manager (having previously served as a `php-src` release manager),
976   while the other one (or two) should be rookies. Hold a vote if necessary (see
977   https://wiki.php.net/rfc/releaseprocess#release_managers_selection).
978
9793. Help the new release managers with their first steps.
980
981
982## New release manager checklist
983
9841. Request membership to the
985   [release managers group](https://github.com/orgs/php/teams/release-managers) on GitHub.
986
9872. Subscribe to the php-announce@lists.php.net mailing list by emailing
988   php-announce+subscribe@lists.php.net
989
9903. Email systems@php.net to get setup for access to downloads.php.net, to be
991   added to the release-managers@php.net distribution list, and to be added to
992   the moderators for php-announce@lists.php.net so you are able to moderate
993   your release announcements.
994
995   Provide the following information in a single email:
996
997   - Preferred Unix username (will also become part of location to download RCs,
998     such as `https://downloads.php.net/~derick/`).
999   - An SSH public key, preferably a new unique one for PHP systems and
1000     projects.
1001   - Read [Machine Access](https://wiki.php.net/systems#machine_access) to set
1002     up access to downloads.php.net through jump hosts, and provide a
1003     `.google_authenticator` file for 2FA.
1004   - Your @php.net email address to use for the release-managers@php.net
1005     distribution list and php-announce@lists.php.net moderator address. This
1006     should preferably not forward to a Gmail address.
1007   - Your GitHub account name, so that your membership to the release managers
1008     group may be approved.
1009
1010   A system admin will then contact you to go through with steps 5 through 8 of
1011   [2FA setup instructions](https://wiki.php.net/systems#fa_setup_instructions).
1012
1013   > �� **Hint** \
1014   > To send email from your @php.net address, you will need to use a custom
1015   > SMTP server. If you use Gmail, you may
1016   > "[Send emails from a different address or alias][]."
1017
1018
10194. Create a [GPG key][] for your @php.net address.
1020
1021   > �� **Tip** \
1022   > If you're new to GPG, follow GitHub's instructions for
1023   > [Generating a new GPG key][].
1024
1025   Publish your key by editing `include/gpg-keys.inc` in the `web-php`
1026   repository. Add a `case` for your username to the `gpg_key_get()` function,
1027   and paste the output from `gpg --fingerprint`. You may also need to update
1028   the `$branches` array in the `gpg_key_get_branches()` function to include
1029   your username alongside your branch.
1030
1031   ```console
1032   ❯ gpg --fingerprint ramsey@php.net
1033   pub   rsa4096 2021-04-26 [SC] [expires: 2025-11-24]
1034   39B6 4134 3D8C 104B 2B14  6DC3 F9C3 9DC0 B969 8544
1035   uid           [ultimate] Ben Ramsey <ramsey@php.net>
1036   sub   rsa4096 2021-04-26 [E] [expires: 2025-11-24]
1037   ```
1038
1039   Have one or more of the other RMs [sign your GPG key][], and publish your
1040   public key to a keyserver:
1041
1042   ```shell
1043   gpg --keyserver keys.openpgp.org --send-keys YOURKEYID
1044   gpg --keyserver keyserver.ubuntu.com --send-keys YOURKEYID
1045   ```
1046
1047   Add your public key to `php-keyring.gpg` in `web-php-distributions`. To do
1048   this, you will need to import all keys from the current PHP keyring file to
1049   your local GPG keyring. You will need to take note of the key IDs for each of
1050   the release managers listed in `php-keyring.gpg`. Then, you will export,
1051   specifying your key ID in addition to the key IDs of every other release
1052   manager. Save this export back to `php-keyring.gpg`, commit the changes,
1053   and push.
1054
1055   ```shell
1056   cd /path/to/repos/php/web-php-distributions
1057   gpg php-keyring.gpg            # lists all keys in the keyring
1058   gpg --import php-keyring.gpg   # imports all keys to your local keyring
1059   gpg --export \
1060       --export-options export-minimal \
1061       --armor \
1062       YOURKEYID F9C39DC0B9698544 DBDB397470D12172 MORE RM KEY IDS ... \
1063       > php-keyring.gpg
1064   gpg php-keyring.gpg  # verify all the keys are present, including yours
1065   git add -p
1066   git commit --gpg-sign=YOURKEYID -m "Update PHP release manager keyring"
1067   git push
1068   ```
1069
1070   `web-php-distributions` is a submodule of `web-php`. You'll now have to update
1071   the commit reference to reflect the change made in web-php-distributions.
1072
1073   ```shell
1074   cd /path/to/repos/php/web-php
1075   git submodule update
1076   cd distributions           # This is the submodule referring to web-php-distributions
1077   git pull origin master
1078   cd ..
1079   git add distributions
1080   git commit --gpg-sign=YOURKEYID -m "Update php-keyring.gpg in distributions"
1081   git push
1082   ```
1083
10845. Make sure you have the following repositories cloned locally:
1085
1086   * https://github.com/php/php-src
1087   * https://github.com/php/web-php
1088   * https://github.com/php/web-qa
1089   * https://github.com/php/web-php-distributions
1090
1091
1092[general availability]: https://en.wikipedia.org/wiki/Software_release_life_cycle#General_availability_(GA)
1093[muscle memory]: https://en.wikipedia.org/wiki/Muscle_memory
1094[Conditional Includes For Git Config]: https://motowilliams.com/2017-05-11-conditional-includes-for-git-config/
1095[Update versions for PHP 8.1.0beta3]: https://github.com/php/php-src/commit/3edd1087c70bee2ec21f0fbec1a575d78a500f15
1096[Update versions for PHP 8.1.6RC1]: https://github.com/php/php-src/commit/40e8ced23898e3069340ca03ea5febc5361015ad
1097[Update NEWS for PHP 8.1.6RC1]: https://github.com/php/php-src/commit/a4fdeaebe419b88e3b4a1f5aba845c2d4e81fd4e
1098[Prepare for PHP 8.1.0RC1]: https://github.com/php/php-src/commit/5764414eb8900ae98020a3c20693f4fb793efa99
1099[Update NEWS for PHP 8.2.0 alpha2]: https://github.com/php/php-src/commit/418f7211f71658d79d934861be20f277db96fe2c
1100[Update NEWS for PHP 8.2.0RC6]: https://github.com/php/php-src/commit/4ccc414961a70200d638ca281a35f893226d74e2
1101[Bump for 8.1.8-dev]: https://github.com/php/php-src/commit/3b6ee1eb19c14c3339ebfcf5c967065a9f828971
1102[GitHub command line tool]: https://cli.github.com
1103[Announce 8.1.0RC3]: https://github.com/php/web-qa/commit/f264b711fd3827803b79bbb342959eae57ea502b
1104[8.1.6RC1]: https://github.com/php/web-qa/commit/e6d61ad7a9d8be0b1cd159af29f3b9cbdde33384
1105[merged upwards as usual]: https://wiki.php.net/vcs/gitworkflow
1106[Update versions for PHP 8.1.7]: https://github.com/php/php-src/commit/d35e577a1bd0b35b9386cea97cddc73fd98eed6d
1107[Update NEWS for PHP 8.1.7]: https://github.com/php/php-src/commit/b241f07f52ca9f87bf52be81817f475e6e727439
1108[Announce PHP 8.1.6]: https://github.com/php/web-php/commit/9f796a96c65f07e45845ec248933bfb0010b94a9
1109[PHP 8.1.6 released]: https://github.com/php/web-qa/commit/bff725f8373cf6fd9d97ba62a8517b19721a4c2e
1110[feature freeze]: https://en.wikipedia.org/wiki/Freeze_(software_engineering)
1111[Prepare for PHP 8.2]: https://github.com/php/php-src/commit/1c33ddb5e5598c5385c4c965992c6e031fd00dd6
1112[Prepare for PHP 8.2 (bis)]: https://github.com/php/php-src/commit/a93e12f8a6dfc23e334339317c97aa35356db821
1113[Add PHP-8.1 to the Git steps page]: https://github.com/php/web-php/commit/1fcd78c2817cf1fbf1a1de2ddec1350be4e26491
1114[Changes to the wiki]: https://wiki.php.net/vcs/gitworkflow?do=diff&rev2%5B0%5D=1617123194&rev2%5B1%5D=1654728193&difftype=sidebyside
1115[migration guide]: https://www.php.net/manual/en/migration81.php
1116[GPG key]: https://en.wikipedia.org/wiki/GNU_Privacy_Guard
1117[Generating a new GPG key]: https://docs.github.com/en/authentication/managing-commit-signature-verification/generating-a-new-gpg-key
1118[sign your GPG key]: https://carouth.com/articles/signing-pgp-keys/
1119[Send emails from a different address or alias]: https://support.google.com/mail/answer/22370?hl=en
1120[security-txt]: https://github.com/php/policies/blob/main/security-policies.rst#making-changes-to-securitytxt
1121