chore: switch to use publish-to-bcr workflow (#3359)

The GitHub App is deprecated, so switch to the more modern workflow.

This will also allow us to eventually use attestations.

Along the way...

* Split up the release workflow into some different sub-jobs
* Run PyPI upload last, as its the most irrevocable step of the process.
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000..f03e021
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,35 @@
+# See https://github.com/bazel-contrib/publish-to-bcr
+name: Publish to BCR
+
+on:
+  # Run the publish workflow after a successful release
+  # Can be triggered from the release.yaml workflow
+  workflow_call:
+    inputs:
+      tag_name:
+        required: true
+        type: string
+    secrets:
+      BCR_PUBLISH_TOKEN:
+        required: true
+  # In case of problems, let release engineers retry by manually dispatching
+  # the workflow from the GitHub UI
+  workflow_dispatch:
+    inputs:
+      tag_name:
+        required: true
+        type: string
+
+jobs:
+  publish:
+    uses: bazel-contrib/publish-to-bcr/.github/workflows/publish.yaml@v1.0.0
+    with:
+      draft: false
+      tag_name: ${{ inputs.tag_name }}
+      # GitHub repository which is a fork of the upstream where the Pull Request will be opened.
+      registry_fork: bazel-contrib/bazel-central-registry
+      attest: false
+    permissions:
+      contents: write
+    secrets:
+      publish_token: ${{ secrets.BCR_PUBLISH_TOKEN }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 7a25c6e..0ed4992 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -35,21 +35,37 @@
         uses: actions/checkout@v5
       - name: Create release archive and notes
         run: .github/workflows/create_archive_and_notes.sh
-      - name: Publish wheel dist
-        if: github.event_name == 'push' || github.event.inputs.publish_to_pypi
-        env:
-          # This special value tells pypi that the user identity is supplied within the token
-          TWINE_USERNAME: __token__
-          # Note, the PYPI_API_TOKEN is for the rules-python pypi user, added by @rickylev on
-          # https://github.com/bazel-contrib/rules_python/settings/secrets/actions
-          TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
-        run: bazel run --stamp --embed_label=${{ github.ref_name }} //python/runfiles:wheel.publish
-      - name: Release
-        uses: softprops/action-gh-release@v2
-        with:
-          # Use GH feature to populate the changelog automatically
-          generate_release_notes: true
-          body_path: release_notes.txt
-          prerelease: ${{ contains(github.ref, '-rc') }}
-          fail_on_unmatched_files: true
-          files: rules_python-*.tar.gz
+
+  release:
+    name: Release
+    uses: softprops/action-gh-release@v2
+    with:
+      # Use GH feature to populate the changelog automatically
+      generate_release_notes: true
+      body_path: release_notes.txt
+      prerelease: ${{ contains(github.ref, '-rc') }}
+      fail_on_unmatched_files: true
+      files: rules_python-*.tar.gz
+
+  publish_bcr:
+    name: Publish to BCR
+    needs: release
+    uses: .github/workflows/publish.yaml
+    with:
+      tag_name: ${{ github.ref_name }}
+    secrets:
+      BCR_PUBLISH_TOKEN: ${{ secrets.BCR_PUBLISH_TOKEN }}
+
+  publish_pypi:
+    # We just want publish_pypi last, since once uploaded, it can't be changed.
+    name: Publish runfiles to PyPI
+    needs: publish_bcr
+    runs-on: ubuntu-latest
+    if: github.event_name == 'push' || github.event.inputs.publish_to_pypi
+    env:
+      # This special value tells pypi that the user identity is supplied within the token
+      TWINE_USERNAME: __token__
+      # Note, the PYPI_API_TOKEN is for the rules-python pypi user, added by @rickylev on
+      # https://github.com/bazel-contrib/rules_python/settings/secrets/actions
+      TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
+    run: bazel run --stamp --embed_label=${{ github.ref_name }} //python/runfiles:wheel.publish