diff --git a/README.md b/README.md index 6f323b8..18c61f7 100644 --- a/README.md +++ b/README.md @@ -355,4 +355,79 @@ post-publish: product_name: winkerberos token: ${{ github.token }} dry_run: ${{ inputs.dry_run }} +``` + +## Python Labs Helper Scripts + +These scripts are opinionated helper scripts for Python releases in MongoDB Labs. +In contrast to the regulare Python scripts, it does not generate the +SSDLC compliance assets or upload anything to S3. + +### Pre-Publish + +Create a new tag. Verify the tag. +Push the commit and tag to the source branch unless `dry_run` is set. + +```yaml +- name: Setup + uses: mongodb-labs/drivers-github-tools/setup@v2 + with: + ... + +- uses: mongodb-labs/drivers-github-tools/python-labs/pre-publishv2 + with: + version_bump_script: ./.github/scripts/bump-version.sh + dry_run: ${{ inputs.dry_run }} +``` + +### Post-publish + +To be run after separately publishing the [Python package](https://github.com/pypa/gh-action-pypi-publish#trusted-publishing). +Handles follow-up tasks related to publishing Python packages. +It will push the following (dev) version to the source branch. +It will create a draft GitHub release with generated release notes. +If `dry_run` is set, nothing will be pushed. + +The jobs should look something like: + +```yaml +publish: + name: Upload release to PyPI + runs-on: ubuntu-latest + environment: release + permissions: + id-token: write + steps: + - name: Download all the dists + uses: actions/download-artifact@v4 + with: + name: all-dist-${{ github.run_id }} + path: dist/ + - name: Publish package distributions to PyPI + if: inputs.dry_run == 'false' + uses: pypa/gh-action-pypi-publish@release/v1 + +post-publish: + needs: [publish] + name: Handle post-publish actions + runs-on: ubuntu-latest + environment: release + permissions: + id-token: write + contents: write + attestations: write + security-events: write + steps: + - name: Setup + uses: mongodb-labs/drivers-github-tools/setup@v2 + with: + ... + + - uses: mongodb-labs/drivers-github-tools/python-labs/post-publish@v2 + with: + following_version: ${{ inputs.following_version }} + version_bump_script: ./.github/scripts/bump-version.sh + product_name: python-bsonjs + token: ${{ github.token }} + dry_run: ${{ inputs.dry_run }} ``` \ No newline at end of file diff --git a/python-labs/post-publish/action.yml b/python-labs/post-publish/action.yml new file mode 100644 index 0000000..2622645 --- /dev/null +++ b/python-labs/post-publish/action.yml @@ -0,0 +1,82 @@ + +name: Python Labs Post-Publish +description: Perform post-release operations for Python Libraries in MongoDB Labs +inputs: + following_version: + description: The following (dev) version + required: false + product_name: + description: The name of the product + required: true + version_bump_script: + description: The version bump script + default: hatch version + working_directory: + description: The working directory for the action + default: "." + tag_template: + description: The template for the git tag + default: "${VERSION}" + repository-url: + description: The PyPI repository URL to use + default: https://upload.pypi.org/legacy/ + token: + description: The GitHub access token + dry_run: + description: Whether this is a dry run + required: true + +runs: + using: composite + steps: + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Install hatch + shell: bash + run: pipx install hatch + - name: Download all the dists + uses: actions/download-artifact@v4 + with: + name: all-dist-${{ github.run_id }} + path: dist/ + - name: Get the package version + shell: bash + run: | + # Handle version already bumped + if [ -z "$VERSION" ]; then + # Extract the version from the sdist name, which must be of the form + # {name}-{version}.tar.gz according to PEP 625. + VERSION=$(ls dist/*.tar.gz | rev | cut -d'-' -f 1 | rev | sed 's/.tar.gz//g') + echo "VERSION=$VERSION" >> $GITHUB_ENV + else + echo "VERSION=$VERSION" >> $GITHUB_ENV + fi + - name: Run GitHub Publish script + shell: bash + id: publish-script + run: ${{ github.action_path }}/post-publish.sh + env: + GH_TOKEN: ${{ inputs.token }} + VERSION: ${{ env.VERSION }} + TAG_TEMPLATE: ${{ inputs.tag_template }} + PRODUCT_NAME: ${{ inputs.product_name }} + DRY_RUN: ${{ inputs.dry_run }} + FOLLOWING_VERSION: ${{ inputs.following_version }} + - name: Ensure a clean repo + shell: bash + run: | + git clean -dffx + git pull origin ${GITHUB_REF} + - name: Set following version + uses: mongodb-labs/drivers-github-tools/bump-version@v2 + if: inputs.dry_run == 'false' + with: + version: ${{ steps.publish-script.outputs.following_version }} + version_bump_script: ${{ inputs.version_bump_script }} + working_directory: ${{ inputs.working_directory }} + - name: Skip Setting following version + shell: bash + if: inputs.dry_run == 'true' + run: | + echo "Dry run, not setting the following version: ${{ steps.publish-script.outputs.following_version }}" >> $GITHUB_STEP_SUMMARY diff --git a/python-labs/post-publish/handle_following_version.py b/python-labs/post-publish/handle_following_version.py new file mode 100644 index 0000000..b2a8ee7 --- /dev/null +++ b/python-labs/post-publish/handle_following_version.py @@ -0,0 +1,21 @@ +import sys +from packaging.version import Version + +version = Version(sys.argv[1]) +new_version = None + +if version.is_devrelease: + # For dev releases, increment the dev release number. + new_version = f"{version.major}.{version.minor}.{version.micro}.dev{version.dev + 1}" +elif version.is_prerelease: + # For pre releases, go back to dev release. + rel_type, rel_num = version.pre + new_version = f"{version.major}.{version.minor}.{version.micro}.{rel_type}{rel_num + 1}" +elif version.micro == 0: + # For minor releases, go to next minor release. + new_version = f"{version.major}.{version.minor + 1}.0.dev0" +else: + # For patch releases, go to the next patch release. + new_version = f"{version.major}.{version.minor}.{version.micro + 1}.dev0" + +print(str(new_version)) \ No newline at end of file diff --git a/python-labs/post-publish/post-publish.sh b/python-labs/post-publish/post-publish.sh new file mode 100755 index 0000000..12fc2cf --- /dev/null +++ b/python-labs/post-publish/post-publish.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -eux + +# Handle the following version. +if [ -z "${FOLLOWING_VERSION}" ]; then + pip install packaging + pushd $GITHUB_ACTION_PATH + FOLLOWING_VERSION=$(python handle_following_version.py $VERSION) + popd +fi +echo "following_version=$FOLLOWING_VERSION" >> $GITHUB_OUTPUT + +if [ "$DRY_RUN" == "false" ]; then + PUSH_CHANGES=true + echo "Creating draft release with attached files" + TITLE="${PRODUCT_NAME} ${VERSION}" + TAG=$(echo "${TAG_TEMPLATE}" | envsubst) + gh release create ${TAG} --draft --verify-tag --title "${TITLE}" --generate-notes + gh release upload ${TAG} $RELEASE_ASSETS/*.* + JSON="url,tagName,assets,author,createdAt" + JQ='.url,.tagName,.author.login,.createdAt,.assets[].name' + echo "\## $TITLE" >> $GITHUB_STEP_SUMMARY + gh release view --json $JSON --jq $JQ ${TAG} >> $GITHUB_STEP_SUMMARY +else + echo "Dry run, not creating GitHub Release" >> $GITHUB_STEP_SUMMARY + ls -ltr $RELEASE_ASSETS + PUSH_CHANGES=false +fi + +# Handle push_changes output. +echo "push_changes=$PUSH_CHANGES" >> $GITHUB_OUTPUT diff --git a/python-labs/pre-publish/action.yml b/python-labs/pre-publish/action.yml new file mode 100644 index 0000000..b12b7da --- /dev/null +++ b/python-labs/pre-publish/action.yml @@ -0,0 +1,72 @@ +name: Python Labs Pre-Publish +description: Perform pre-release operations for Python Libraries in MongoDB Labs +inputs: + tag_template: + description: The template for the git tag + default: "${VERSION}" + tag_message_template: + description: The template for the git tag message + default: "Release ${VERSION}" + working_directory: + description: The working directory for the action + default: "." + dry_run: + description: Whether this is a dry run + required: true + +outputs: + version: + description: The output version to use + value: ${{ steps.version.outputs.version }} + +runs: + using: composite + steps: + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Install hatch + shell: bash + working-directory: ${{ inputs.working_directory }} + run: | + pipx install hatch + pip install build + - name: Handle inputs + shell: bash + working-directory: ${{ inputs.working_directory }} + env: + DRY_RUN: "${{ inputs.dry_run }}" + run: | + set -eux + # Handle DRY_RUN + if [ "$DRY_RUN" != "true" ]; then + export PUSH_CHANGES=true + else + export PUSH_CHANGES=false + fi + echo "PUSH_CHANGES=$PUSH_CHANGES" >> $GITHUB_ENV + # Handle version + # Extract the version from the sdist name, which must be of the form + # {name}-{version}.tar.gz according to PEP 625. + python -m build --sdist . + VERSION=$(ls dist/*.tar.gz | rev | cut -d'-' -f 1 | rev | sed 's/.tar.gz//g') + echo "VERSION=$VERSION" >> $GITHUB_ENV + rm -rf dist + - name: Tag version + uses: mongodb-labs/drivers-github-tools/tag-version@v2 + with: + version: ${{ env.VERSION }} + tag_template: ${{ inputs.tag_template }} + tag_message_template: ${{ inputs.tag_message_template }} + push_tag: ${{ env.PUSH_CHANGES }} + - name: Handle version output + shell: bash + id: version + run: | + if [ "${{ inputs.dry_run}}" == 'true' ]; then + echo "version=${{ github.ref }}" >> $GITHUB_OUTPUT + else + export VERSION=${{ env.VERSION }} + export TAG=$(echo "${{ inputs.tag_template }}" | envsubst) + echo "version=$TAG" >> $GITHUB_OUTPUT + fi \ No newline at end of file diff --git a/python/pre-publish/action.yml b/python/pre-publish/action.yml index 914aa87..e4e2a4e 100644 --- a/python/pre-publish/action.yml +++ b/python/pre-publish/action.yml @@ -38,6 +38,7 @@ runs: pip install build - name: Handle inputs shell: bash + working-directory: ${{ inputs.working_directory }} env: VERSION: "${{ inputs.version }}" DRY_RUN: "${{ inputs.dry_run }}"