diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c19fcbe67..59f41037e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,7 +5,7 @@ on: workflow_dispatch: inputs: version: - description: "The version to be released. This is checked for consistency with the branch name and configuration" + description: "The version to be released in PECL format (e.g. 1.19.1, 1.20.0beta1)" required: true type: "string" jira-version-number: @@ -53,6 +53,13 @@ jobs: contents: write steps: + - name: "Check version number format" + run: | + if ! [[ "${{ inputs.version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+((alpha|beta|RC)[0-9]+)?$ ]]; then + echo '❌ Version ${{ inputs.version }} does not match expected format' >> $GITHUB_STEP_SUMMARY + exit 1 + fi + - name: "Create release output" run: echo '🎬 Release process for version ${{ inputs.version }} started by @${{ github.triggering_actor }}' >> $GITHUB_STEP_SUMMARY @@ -76,31 +83,12 @@ jobs: with: php-version: "${{ matrix.php-version }}" - - name: "Update version information to stable release" - run: ./bin/update-release-version.php to-stable - - - name: "Read current package version" - run: echo "PACKAGE_VERSION=$(./bin/update-release-version.php get-version)" >> "$GITHUB_ENV" - - # Sanity check - the version from the input and the one determined by phongo_version.h need to be the same - - name: "Check version for consistency" - if: ${{ inputs.version != env.PACKAGE_VERSION }} - # We exit with an error to abort the workflow. This is only run if the versions don't match - run: | - echo '❌ Release failed due to version mismatch: expected ${{ inputs.version }}, got ${{ env.PACKAGE_VERSION }} from code' >> $GITHUB_STEP_SUMMARY - exit 1 - - # - # Preliminary checks done - commence the release process - # - - name: "Create package commit" uses: mongodb-labs/drivers-github-tools/bump-version@v2 with: version: ${{ inputs.version }} - # Use get-version as a dummy as a version_bump_script is required - # We run the bump script manually earlier so we can sanity-check the version number and print nice output - version_bump_script: "./bin/update-release-version.php get-version" + # Note: this script will fail and abort if the requested version can't be released + version_bump_script: "./bin/update-release-version.php release" commit_template: 'Package ${VERSION}' # Don't push changes as we're creating a second commit later push_commit: false @@ -117,7 +105,7 @@ jobs: uses: mongodb-labs/drivers-github-tools/bump-version@v2 with: version: ${{ inputs.version }} - version_bump_script: "./bin/update-release-version.php to-next-patch-dev" + version_bump_script: "./bin/update-release-version.php to-next-dev" commit_template: 'Back to -dev' # Don't push commit, we still need to merge up push_commit: false @@ -155,7 +143,11 @@ jobs: EOL - name: "Create draft release" - run: echo "RELEASE_URL=$(gh release create ${{ inputs.version }} --target ${{ github.ref_name }} --title "${{ inputs.version }}" --notes-file release-message --draft)" >> "$GITHUB_ENV" + run: | + if [[ "${{ inputs.version }}" =~ (alpha|beta|RC) ]]; then + PRERELEASE="--prerelease --latest=false" + fi + echo "RELEASE_URL=$(gh release create ${{ inputs.version }} ${PRERELEASE} --target ${{ github.ref_name }} --title "${{ inputs.version }}" --notes-file release-message --draft)" >> "$GITHUB_ENV" - name: "Set summary" run: | diff --git a/RELEASING.md b/RELEASING.md index 14db48599..561c91881 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -46,13 +46,26 @@ enter the version number and the corresponding JIRA version ID for the release. This version ID can be obtained from a link in the "Version" column on the [PHPC releases page](https://jira.mongodb.org/projects/PHPC?selectedItem=com.atlassian.jira.jira-projects-plugin%3Arelease-page&status=unreleased). -The automation will then create and push the necessary commits and tag, create a -draft release, and trigger the packaging builds for the newly created tag. The -release is created in a draft state and can be published once the release notes -have been updated. - -Alternatively, you may follow the [manual release process](#manual-release-process) -before continuing with the next section. +The automation will create and push the necessary commits and tag, create a +draft release, trigger the packaging builds for the newly created tag, and +publish all required SSDLC assets. The release is created in a draft state and +can be published once the release notes have been updated. + +Pre-releases (alpha, beta and RC stability) can be released using the automation +as well. When entering a pre-release version number, make sure to not include a +dash before the stability, e.g. `1.20.0beta1` not `1.20.0-beta1`. PECL versions +do not include a dash before the stability. GitHub Releases for pre-release +versions will be marked as such and will not be marked as "latest" release. +Examples for valid pre-release versions include: +* `1.20.0alpha1` +* `1.20.0beta2` +* `1.20.0RC1` (note the upper-case `RC` suffix) + +## Publish release notes + +The GitHub release notes are created as a draft, and without any release +highlights. Fill in release highlights and publish the release notes once the +entire release workflow has completed. ## Upload package to PECL @@ -75,180 +88,7 @@ in the MongoDB documentation must be updated to account for new releases. Make sure to update both MongoDB and Language compatibility tables, as shown in [this pull request](https://github.com/mongodb/docs-ecosystem/pull/642). -## Handle merge-up pull request - -After the release automation pushes changes to the stable branch the release was -created from, the merge automation will create a new pull request to merge these -changes into the next versioned branch. Since version changes always create a -conflict, follow the "Ignoring Changes" section in the pull request to resolve -the conflicts and merge the pull request once the build completes. - ## Announce release Significant release announcements should also be posted in the [MongoDB Product & Driver Announcements: Driver Releases](https://www.mongodb.com/community/forums/tags/c/announcements/driver-releases/110/php) forum. - -## Manual release process - -The following steps outline the manual release process. These are preserved -for historical reasons and releases that are currently not supported by the -release automation (e.g. beta releases). These steps are meant to be run instead -of [triggering the release workflow](#trigger-the-release-workflow). The -instructions assume that the steps preceding the release workflow have been -completed successfully. - -The command examples below assume that the canonical "mongodb" repository has -the remote name "mongodb". You may need to adjust these commands if you've given -the remote another name (e.g. "upstream"). The "origin" remote name was not used -as it likely refers to your personal fork. - -It helps to keep your own fork in sync with the "mongodb" repository (i.e. any -branches and tags on the main repository should also exist in your fork). This -is left as an exercise to the reader. - -### Update version info - -The PHP driver uses [semantic versioning](http://semver.org/). Do not break -backwards compatibility in a non-major release or your users will kill you. - -Before proceeding, ensure that the `master` branch is up-to-date with all code -changes in this maintenance branch. This is important because we will later -merge the ensuing release commits up to master with `--strategy=ours`, which -will ignore changes from the merged commits. - -Update the version and stability constants in `phongo_version.h` for the stable -release: - -```shell -$ ./bin/update-release-version.php to-stable -``` - -The Makefile targets for creating the PECL package depend on these constants, so -you must rebuild the extension after updating `phongo_version.h`. - -> [!NOTE] -> If this is an alpha or beta release, the version string should include the -> X.Y.Z version followed by the stability and an increment. For instance, the -> first beta release in the 1.4.0 series would be "1.4.0beta1". Alpha and beta -> releases use "alpha" and "beta" stability strings, respectively. Release -> candidates (e.g. "1.4.0RC1") also use "beta" stability. See -> [Documenting release stability and API stability](https://pear.php.net/manual/en/guide.developers.package2.stability.php) -> for more information. For each change to the suffixes of -> `PHP_MONGODB_VERSION`, increment the last digit of -> `PHP_MONGODB_VERSION_DESC`. - -### Build PECL package - -Create the PECL package description file with `make package.xml`. This creates -a `package.xml` file from a template. Version, author, and file information will -be filled in, but release notes must be copied manually from JIRA. - -After copying release notes, use `make package` to create the package file (e.g. -`mongodb-X.Y.Z.tgz`) and ensure that it can be successfully installed: - -``` -$ pecl install -f mongodb-X.Y.Z.tgz -``` - -### Update version info - -Commit the modified `phongo_version.h` file and push this change: - -``` -$ git commit -m "Package X.Y.Z" phongo_version.h -$ git push mongodb -``` - -### Tag the release - -Create a tag for the release and push: - -``` -$ git tag -a -m "Release X.Y.Z" X.Y.Z -$ git push mongodb --tags -``` - -Pushing the new tag will start the packaging process which provides the PECL -and Windows packages that should be attached to the release. - -### Release PECL package - -The PECL package may be published via the -[Release Upload](https://pecl.php.net/release-upload.php) form. You will have -one chance to confirm the package information after uploading. - -### Update version info back to dev - -After tagging, the version and stability constants in `phongo_version.h` should -be updated back to development status: - -```shell -$ ./bin/update-release-version.php to-next-patch-dev -``` - -Commit and push this change: - -``` -$ git commit -m "Back to -dev" phongo_version.h -$ git push mongodb -``` - -> [!NOTE] -> If this is an alpha, beta, or RC release, the version string should increment -> the stability sequence instead of the patch version. For example, if the -> constants were originally "1.4.0-dev" and "devel" and then changed to -> "1.4.0beta1" and "beta" for the first beta release, this step would see them -> ultimately changed to "1.4.0beta2-dev" and "devel". - -### Publish release notes - -The following template should be used for creating GitHub release notes via -[this form](https://github.com/mongodb/mongo-php-driver/releases/new). The PECL -package may also be attached to the release notes. - -```markdown -The PHP team is happy to announce that version X.Y.Z of the [mongodb](https://pecl.php.net/package/mongodb) PHP extension is now available on PECL. - -**Release Highlights** - - - -A complete list of resolved issues in this release may be found in [JIRA]($JIRA_URL). - -**Documentation** - -Documentation is available on [PHP.net](https://php.net/set.mongodb). - -**Installation** - -You can either download and install the source manually, or you can install the extension with: - - pecl install mongodb-X.Y.Z - -or update with: - - pecl upgrade mongodb-X.Y.Z - -Windows binaries are attached to the GitHub release notes. -``` - -> [!NOTE] -> If this is an alpha or beta release, the installation examples should refer to -> the exact version (e.g. "mongodb-1.8.0beta2"). This is necessary because PECL -> prioritizes recent, stable releases over any stability preferences -> (e.g. "mongodb-beta"). - -The URL for the list of resolved JIRA issues will need to be updated with each -release. You may obtain the list from -[this form](https://jira.mongodb.org/secure/ReleaseNote.jspa?projectId=12484). - -If commits from community contributors were included in this release, append the -following section: - -```markdown -**Thanks** - -Thanks for our community contributors for X.Y.Z: - -* [$CONTRIBUTOR_NAME](https://github.com/$GITHUB_USERNAME) -``` diff --git a/bin/update-release-version.php b/bin/update-release-version.php index 79c7fe88e..9731cdd13 100755 --- a/bin/update-release-version.php +++ b/bin/update-release-version.php @@ -9,9 +9,11 @@ function usage() echo << +{$argv[0]} [] Commands: + release: Release the given version (requires second argument) + to-next-dev: Update to the next version following the current version to-stable: Mark the current version as stable to-next-patch-dev: Update to the next patch development version to-next-minor-dev: Update to the next minor development version @@ -50,6 +52,31 @@ function read_release_version(string $filename): array return $versions; } +function parse_release_version(string $version): array +{ + // Regex copied from https://github.com/pear/pear-core/blob/6f4c3a0b134626d238d75a44af01a2f7c4e688d9/PEAR/Common.php#L32 + if (! preg_match('#^(?\d+)\.(?\d+)\.(?\d+)(?:(?(?:alpha|beta|RC))(?\d+))?$#', $version, $matches)) { + throw new Exception(sprintf('Given version "%s" is not in the PEAR version format')); + } + + $stability = 'stable'; + if (isset($matches['stability'])) { + // PEAR does not have a stability for RC releases, so use beta instead + $stability = $matches['stability'] == 'RC' ? 'beta' : $matches['stability']; + } + + return [ + 'version' => $version, + 'stability' => $stability, + 'versionComponents' => [ + $matches['major'], + $matches['minor'], + $matches['patch'], + 0, + ], + ]; +} + function write_release_version(string $filename, array $version): void { if (! is_file($filename)) { @@ -140,6 +167,46 @@ function get_next_minor_version(array $versions): array ]; } +function get_next_release_version(array $versions, string $releaseVersion): array +{ + $releaseVersion = parse_release_version($releaseVersion); + + // When bumping to the specified release version, check if the major, minor, and patch versions match what's currently in the file + if (array_slice($versions['versionComponents'], 0, 3) !== array_slice($releaseVersion['versionComponents'], 0, 3)) { + throw new Exception(sprintf('Cannot bump version "%s" to version "%s".', $versions['version'], $releaseVersion['version'])); + } + + // Now, re-use the existing version components to copy over the previous build number used for DLLs + $releaseVersion['versionComponents'] = $versions['versionComponents']; + + return $releaseVersion; +} + +function get_next_dev_version(array $versions): array +{ + $versionComponents = $versions['versionComponents']; + + // We're dealing with a pre-release. The next version is a devel version of the corresponding stable release + // Examples: + // 1.19.1snapshot => 1.19.1dev + // 1.20.0alpha1 => 1.20.0dev + // 1.20.0beta1 => 1.20.0dev + // 1.20.0RC1 => 1.20.0dev + if ($versions['stability'] != 'stable') { + // Increase the build number for unique DLL versions + $versionComponents[3]++; + + return [ + 'version' => get_version_string_from_components($versionComponents) . 'dev', + 'stability' => 'devel', + 'versionComponents' => $versionComponents, + ]; + } + + // For all other releases, return the next patch version + return get_next_patch_version($versions); +} + // Allow 2 arguments as the bump-version action always passes a version number, even when not needed if (! in_array($argc, [2, 3])) { usage(); @@ -153,6 +220,18 @@ function get_next_minor_version(array $versions): array exit(0); + case 'release': + if ($argc !== 3) { + usage(); + } + + $newVersion = get_next_release_version($currentVersion, $argv[2]); + break; + + case 'to-next-dev': + $newVersion = get_next_dev_version($currentVersion); + break; + case 'to-stable': $newVersion = get_stable_version($currentVersion); break;