Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
name: CI (unit)
# pull_request only. A push trigger alongside it ran the whole suite twice on the same
# SHA, and the duplicate legs raced each other against the Stream app several SDK repos
# share. main and *.x are covered by release.yml, which runs this same reusable workflow
# as the gate before tagging.
on:
push:
branches: [ "**" ]
pull_request:
branches: [ "**" ]

Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/pr_title.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Lint PR title

on:
pull_request:
types: [opened, edited, reopened, synchronize]

permissions:
pull-requests: read

jobs:
pr_title:
name: 👮 Conventional PR title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
292 changes: 126 additions & 166 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,223 +1,183 @@
name: Release

on:
push:
branches:
- main
- '*.x'
workflow_dispatch:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Should Fix] No manual republish path survives, and the one retry that works expires.

The old workflow's workflow_dispatch took version_bump (patch/minor/major) and use_current_version, which computed from the latest tag and gave an admin a one-click cut at any time. This bare workflow_dispatch runs release-please, which finds no autorelease: pending PR after a tag already exists and so outputs release_created false, skipping publish.

So after a failed publish the only recovery is "Re-run failed jobs" on the original run, and GitHub retires re-runs after a finite window. Past it, the tagged and GitHub-Released version can never reach PyPI; the only way forward is landing a new commit and cutting a new version. README.md:264 presents the re-run as the retry path without saying it is the only one or that it expires.

In fairness, use_current_version was already broken on main, since pyproject.toml has been stale at 4.1.0 since #274. What is genuinely lost is the tag-derived manual cut.

Minor, same line: workflow_dispatch is not restricted to main and *.x the way push is, and target-branch: ${{ github.ref_name }} follows whatever ref it is dispatched from. Dispatching from a feature branch grooms a Release PR against that branch with contents: write and pull-requests: write behind it. Stray Release PRs rather than a bad tag, but a job-level guard closes it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8d94e3e, both halves.

workflow_dispatch now takes publish_tag. Set it to an existing tag and the run skips release-please entirely and goes straight to build and publish for that tag, so a tagged version can still reach PyPI after GitHub has retired the original run. Left empty it behaves as a normal release run. The README says this instead of presenting the re-run as the retry path.

The branch guard is on release-pr and detect: github.ref_name == 'main' || endsWith(github.ref_name, '.x'). Dispatching from a feature branch now does nothing.

Not restoring the tag-derived manual cut. Under release-please a version is a merged Release PR, and a second path that invents one would put the manifest and the tags out of step, which is the failure this PR exists to remove. Release-As: covers the real need.

inputs:
version_bump:
description: 'Version bump type for manual release'
required: true
default: 'patch'
type: choice
options:
- patch
- minor
- major
use_current_version:
description: 'Skip version bump and publish the version already set in pyproject.toml'
publish_tag:
description: 'Existing tag to (re)publish to PyPI, e.g. v6.1.1. Leave empty for a normal release run.'
required: false
default: false
type: boolean
pull_request:
types: [closed]
branches:
- main

concurrency:
group: release-${{ github.event.pull_request.base.ref || github.ref_name }}
cancel-in-progress: false
default: ''

permissions:
contents: read

concurrency:
group: release-${{ github.ref_name }}
cancel-in-progress: false

jobs:
prepare:
name: Prepare release
if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true
# Reversible half: keep the Release PR current. Never gated.
release-pr:
name: Release PR
if: >-
(github.event_name == 'push' || inputs.publish_tag == '') &&
(github.ref_name == 'main' || endsWith(github.ref_name, '.x'))
runs-on: ubuntu-latest
outputs:
should_release: ${{ steps.release_meta_final.outputs.should_release }}
bump: ${{ steps.release_meta_final.outputs.bump }}
previous_version: ${{ steps.release_meta_final.outputs.previous_version }}
version: ${{ steps.release_meta_final.outputs.version }}
tag: ${{ steps.release_meta_final.outputs.tag }}
timeout-minutes: 5
permissions:
contents: write
issues: write
pull-requests: write
steps:
- uses: actions/checkout@v5
- uses: googleapis/release-please-action@v4

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Must Fix] The tag and the GitHub Release are created before any test runs, and a red suite cannot be undone.

This job has no needs:, so release-please-action creates both the tag and the GitHub Release as soon as a merged Release PR is pending. Tests come after (lines 39 to 55) and only gate publish.

The old workflow gated both on the suite. From the base commit:

$ git show 242d57c6:.github/workflows/release.yml | sed -n '117,120p'
  release:
    name: 🚀 Release
    needs: [prepare, test-unit, test-integration]

with git push origin "${TAG}" and ncipollo/release-action@v1 inside that job.

State after a failed test-integration now: main carries the bumped pyproject.toml, uv.lock and CHANGELOG.md; the tag exists; the GitHub Release is public; PyPI has nothing. pip install getstream==X.Y.Z 404s on a version both the repo and the Releases page advertise.

It is also not re-runnable in the obvious way. After tagging, release-please swaps the label on the merged Release PR (manifest.ts:1319, autorelease: pending to autorelease: tagged) and its release scan skips any PR without the pending label (manifest.ts:1155). So a fresh run, including workflow_dispatch, outputs release_created false and publish never runs. Only "Re-run failed jobs" works, because it reuses this job's cached outputs. "Re-run all jobs" permanently skips publish.

Fix: split the action in two, as the getstream-go pilot does. Call it once with skip-github-release: true to keep the Release PR fresh, run the gate, then call it again with skip-github-pull-request: true to tag and release, then publish. The cost here is that the gate has to run before you know a release is pending, so a cheaper shape is a job that detects the pending Release PR, runs the suite only then, and only then calls the release half.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8d94e3e. Restructured rather than patched, because the getstream-go two-call shape assumes a cheap gate and this one is a full matrix.

detect finds the merged Release PR carrying autorelease: pending and outputs its merge_commit_sha. Tests run only when one is pending, and against that sha rather than the branch tip, so what is tested is what gets tagged. release needs both matrices and calls the action with skip-github-pull-request: true. release-pr still runs unguarded with skip-github-release: true, so the Release PR stays fresh whatever the suite does.

The relabel trap you describe is why the ordering matters and also why publish now has a second entrance: see the reply on the workflow_dispatch thread.

with:
fetch-depth: 0
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref || github.ref_name }}

- name: Skip when PR is already released
id: already_released
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "value=false" >> "$GITHUB_OUTPUT"
else
# Idempotency is tracked on the release tag (annotated with the PR number
# in "Create release tag"), not on a default-branch commit: the version
# bump is no longer pushed to the protected default branch.
if git for-each-ref refs/tags --format='%(contents)' | grep -q "(pr #${{ github.event.pull_request.number }})"; then
echo "value=true" >> "$GITHUB_OUTPUT"
else
echo "value=false" >> "$GITHUB_OUTPUT"
fi
fi

- name: Determine version bump (from PR metadata)
id: release_meta
if: github.event_name == 'pull_request' && steps.already_released.outputs.value != 'true'
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
target-branch: ${{ github.ref_name }}
skip-github-release: true

# Tagging and the GitHub Release are irreversible, so the suite has to run before
# them, which means knowing a release is pending before the suite starts. The tag
# lands on the merged Release PR's merge commit, not on this branch's tip, so that
# commit is also what gets tested.
detect:
name: Detect pending release
if: >-
(github.event_name == 'push' || inputs.publish_tag == '') &&
(github.ref_name == 'main' || endsWith(github.ref_name, '.x'))
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
pull-requests: read
outputs:
pending: ${{ steps.find.outputs.pending }}
sha: ${{ steps.find.outputs.sha }}
steps:
- name: Find a merged Release PR waiting to be tagged
id: find
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
python3 scripts/release/bump_version.py \
--title "$PR_TITLE" \
--output "$GITHUB_OUTPUT"

- name: Determine version bump (manual)
id: release_meta_manual
if: github.event_name == 'workflow_dispatch'
GH_TOKEN: ${{ github.token }}
run: |
python3 scripts/release/bump_version.py \
--manual-bump "${{ github.event.inputs.version_bump }}" \
--use-current-version "${{ github.event.inputs.use_current_version }}" \
--output "$GITHUB_OUTPUT"

- name: Consolidate release metadata
id: release_meta_final
run: |
if [ "${{ steps.already_released.outputs.value }}" = "true" ]; then
echo "should_release=false" >> "$GITHUB_OUTPUT"
echo "bump=none" >> "$GITHUB_OUTPUT"
sha="$(gh api "repos/${GITHUB_REPOSITORY}/pulls?state=closed&base=${GITHUB_REF_NAME}&sort=updated&direction=desc&per_page=50" \
--jq '[.[] | select(.merged_at != null and ([.labels[].name] | index("autorelease: pending")))] | .[0].merge_commit_sha // empty')"
if [ -z "$sha" ]; then
echo "No pending release."
echo "pending=false" >> "$GITHUB_OUTPUT"
exit 0
fi
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "should_release=${{ steps.release_meta_manual.outputs.should_release }}" >> "$GITHUB_OUTPUT"
echo "bump=${{ steps.release_meta_manual.outputs.bump }}" >> "$GITHUB_OUTPUT"
echo "previous_version=${{ steps.release_meta_manual.outputs.previous_version }}" >> "$GITHUB_OUTPUT"
echo "version=${{ steps.release_meta_manual.outputs.version }}" >> "$GITHUB_OUTPUT"
echo "tag=${{ steps.release_meta_manual.outputs.tag }}" >> "$GITHUB_OUTPUT"
else
echo "should_release=${{ steps.release_meta.outputs.should_release }}" >> "$GITHUB_OUTPUT"
echo "bump=${{ steps.release_meta.outputs.bump }}" >> "$GITHUB_OUTPUT"
echo "previous_version=${{ steps.release_meta.outputs.previous_version }}" >> "$GITHUB_OUTPUT"
echo "version=${{ steps.release_meta.outputs.version }}" >> "$GITHUB_OUTPUT"
echo "tag=${{ steps.release_meta.outputs.tag }}" >> "$GITHUB_OUTPUT"
fi
echo "Pending release will be tagged at $sha."
echo "pending=true" >> "$GITHUB_OUTPUT"
echo "sha=$sha" >> "$GITHUB_OUTPUT"

test-unit:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Should Fix] Every release commit now runs the unit matrix twice, at the same time, against the same shared Stream app.

ci.yml:3-4 triggers on push: branches: [ "**" ], which includes main, and calls the same reusable workflow with the same marker: 'not integration'. The Release PR merge is a push to main, so ci.yml's unit and this test-unit both fire on the identical SHA.

That is 12 jobs duplicated per release (ruff, typecheck, 5 test-non-video, 5 test-video), and 5 of the duplicates are live legs hitting the app that several SDK repos share. Tests that mutate app-global state feel it directly, for example tests/test_chat_misc.py:34 test_update_app_settings_event_hooks, which calls update_app(event_hooks=[]) with no save or restore, and tests/test_chat_misc.py:325 test_file_upload_config, which read-back asserts exact equality on a global config.

This pairing is new. The old trigger was pull_request: types: [closed], so the release run's ref was refs/pull/N/merge and the two never shared a ref.

unverified: whether the two runs also collide in run_tests.yml:10, whose group is ${{ github.workflow }}-${{ github.ref }}-${{ inputs.marker }}. Two of the three parts are already identical here, so the only discriminator is github.workflow. If it resolves to the caller (Release vs CI (unit)) both runs proceed and you pay the duplicate. If it resolves to the called workflow (_run-tests) they share a group with cancel-in-progress: true, one cancels the other, and a cancelled needs job makes publish skip rather than fail, which is the quiet direction. Settle it by echoing ${{ github.workflow }} in one job, or by checking the CI (unit) run's conclusion on the first release push.

Either resolution is closed by the same fix: drop main and *.x from ci.yml's push filter, or drop test-unit here and reduce publish to needs: [release, test-integration]. test-integration is the only signal ci.yml does not already produce.

Related, and worth knowing when picking: all nine @pytest.mark.integration tests live under tests/rtc/ or the two MANUAL_PATHS files, so make test MARKER="integration" matches nothing and the test-non-video legs of test-integration are no-ops (Makefile:59-60 exit-5 branch). The live chat and feeds suites actually run under the job named Test (unit).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8d94e3e: ci.yml is now branches-ignore: [main, "*.x"].

Took that direction rather than dropping test-unit because after the other must-fix, the matrix is the gate in front of an irreversible tag, so it has to be a needs: edge here. Leaving ci.yml on main would have kept the duplicate without adding a gate.

Left your unverified: unresolved on purpose: with the collision gone, whether github.workflow resolves to caller or callee stops being load-bearing. Worth knowing that main now has no CI outside a release push; PR runs are on refs/pull/N/merge, so the merged tree is still covered.

Noted on the integration marker matching nothing outside tests/rtc/. Left as is, it is the gate the old workflow had, and narrowing it is a separate change.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up, with evidence. The branches-ignore half-measure was not enough and the PR-branch duplicate you did not raise is the same bug. On 3613936 two CI (unit) runs started five seconds apart on the identical SHA, one from push and one from pull_request:

pull_request  failure  2026-09-11T15:34:56Z  3613936
push          success  2026-09-11T15:34:51Z  3613936

Three non-video legs failed in the pull_request run, on GET /api/v2/app returning 500 and httpx.ReadTimeout, while the push run of the same commit was green. Same tree, same second, opposite results, so it is the shared-app race and not the diff.

Fixed in 60db296: ci.yml is pull_request only now, no push trigger at all. That covers PR branches, and on the merge ref rather than the branch tip. main and *.x stay covered by release.yml, which runs the same reusable workflow as the gate before tagging. A branch with no PR now gets no CI, which is the accepted cost.

name: Test (unit)
needs: prepare
if: needs.prepare.outputs.should_release == 'true'
needs: detect
if: needs.detect.outputs.pending == 'true'
uses: ./.github/workflows/run_tests.yml
with:
marker: 'not integration'
secrets: inherit

test-integration:
name: Test (integration)
needs: prepare
if: needs.prepare.outputs.should_release == 'true'
needs: detect
if: needs.detect.outputs.pending == 'true'
uses: ./.github/workflows/run_tests.yml
with:
marker: 'integration'
secrets: inherit

# Irreversible half.
release:
name: 🚀 Release
needs: [prepare, test-unit, test-integration]
if: needs.prepare.outputs.should_release == 'true'
name: 🚀 Tag and release
needs: [detect, test-unit, test-integration]
if: needs.detect.outputs.pending == 'true'
runs-on: ubuntu-latest
environment: pypi
timeout-minutes: 5
permissions:
contents: write
id-token: write
issues: write
pull-requests: write
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref || github.ref_name }}

- uses: ./.github/actions/python-uv-setup

- name: Apply version bump
# The suite ran against this workflow's own commit, while the tag lands on the
# merged Release PR's merge commit. They are the same commit on the path that
# gets here, a push of that merge. They diverge on a dispatch after the branch
# has moved, which would tag a tree nothing tested, so refuse instead. Recovery
# is "Re-run failed jobs" on the run for the merge itself.
- name: Refuse to tag a commit the suite did not run on
env:
VERSION: ${{ needs.prepare.outputs.version }}
TESTED: ${{ github.sha }}
PENDING: ${{ needs.detect.outputs.sha }}
run: |
python3 - <<'PY'
import os, re
from pathlib import Path
version = os.environ['VERSION']
path = Path('pyproject.toml')
text = path.read_text(encoding='utf-8')
pattern = re.compile(r'^version\s*=\s*"\d+\.\d+\.\d+"\s*$', re.MULTILINE)
new_text, count = pattern.subn(f'version = "{version}"', text, count=1)
if count == 0:
raise SystemExit('Could not update version line in pyproject.toml')
path.write_text(new_text, encoding='utf-8')
PY

# Commit the bump locally only, so the release tag points at a tree with the
# correct version. It is intentionally NOT pushed to the protected default
# branch (which rejects direct pushes). Versioning is driven by tags, not by
# pyproject.toml on the default branch (see bump_version.py: find_latest_semver_tag).
- name: Commit version bump (local, for tagging only)
env:
VERSION: ${{ needs.prepare.outputs.version }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add pyproject.toml
if git diff --cached --quiet; then
echo "No version changes to commit."
else
git commit -m "chore(release): v${VERSION}"
if [ "$TESTED" != "$PENDING" ]; then
echo "::error::The pending release is tagged at $PENDING but this run tested $TESTED."
echo "::error::Re-run the workflow run for $PENDING instead of dispatching from the branch tip."
exit 1
fi
echo "Tagging $PENDING, which is the commit the suite ran on."

- name: Create release tag
- uses: googleapis/release-please-action@v4
id: release
with:
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
target-branch: ${{ github.ref_name }}
skip-github-pull-request: true

# Chained rather than triggered on the release event, because a GitHub Release
# created with GITHUB_TOKEN starts no new workflow run. Also reachable on its own
# through workflow_dispatch with publish_tag, which is the recovery path once
# GitHub has retired the original run and "Re-run failed jobs" is gone.
publish:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Should Fix] release and publish have no timeout-minutes, and the release concurrency group never cancels.

Both fall back to the 360 minute default; only test-non-video and test-video are bounded (run_tests.yml:56, :82). With concurrency: cancel-in-progress: false (line 17), a single hung publish holds release-main for six hours and every subsequent release queues behind it.

Fix: timeout-minutes: 5 on release and timeout-minutes: 15 on publish.

Separately on this job: the tests and the publish build different trees. Every checkout in run_tests.yml is bare (:27, :38, :59, :85) so the tests run on github.sha, while line 70 checks out needs.release.outputs.tag_name. They match on the happy path, but diverge on a workflow_dispatch re-run after main has moved, since release-please tags the merged Release PR's merge commit rather than the branch tip. README.md:264 claims the matrix runs "on the tagged commit", which is not what the workflow does. Either add a ref input to run_tests.yml and pass the tag, or reword the README.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both fixed in 8d94e3e. timeout-minutes: 5 on release-pr, detect and release, 15 on publish.

The tree divergence is closed rather than documented around: run_tests.yml takes a ref input, all four checkouts honour it, and detect passes the pending Release PR's merge commit. So the README claim that the matrix runs on the tagged commit is now true on the dispatch path too, not only the happy path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correction on the second half of this. The ref input is reverted in 3613936; run_tests.yml is byte-identical to main again.

Passing a ref into the reusable workflow gave CodeQL four high actions/cache-poisoning alerts: it checks out that ref and then populates the uv cache the default branch reuses. Not reachable from untrusted data on any path here, since the only value passed came from a merged Release PR's merge_commit_sha, but it is a real class and it was not worth carrying for the edge it closed.

Instead the tests run on the workflow's own commit and the release job refuses to tag when that is not the commit the pending Release PR would be tagged at. On the path that reaches it, a push of that merge, the two are the same commit. That is a stronger guarantee than the ref input gave: previously a dispatch could still tag the merge commit after testing it, now a dispatch that would tag anything the run did not test fails instead. README reworded to match.

The timeout-minutes half of your comment is unaffected and still fixed in 8d94e3e.

name: 📦 Publish to PyPI
needs: release
if: >-
!cancelled() &&
(inputs.publish_tag != '' || needs.release.outputs.release_created == 'true')
runs-on: ubuntu-latest
timeout-minutes: 15
# PyPI Trusted Publishing is bound to this workflow file name and this environment.
environment: pypi
permissions:
contents: read
id-token: write
steps:
- name: Resolve tag
id: target
env:
TAG: ${{ needs.prepare.outputs.tag }}
PR: ${{ github.event.pull_request.number }}
PUBLISH_TAG: ${{ inputs.publish_tag }}
RELEASE_TAG: ${{ needs.release.outputs.tag_name }}
run: |
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
echo "Tag ${TAG} already exists; skipping tag creation."
exit 0
fi
# Annotate the tag with the trigger; the PR number is used by the
# "Skip when PR is already released" idempotency check.
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
git tag -a "${TAG}" -m "chore(release): ${TAG} (manual)"
else
git tag -a "${TAG}" -m "chore(release): ${TAG} (pr #${PR})"
fi
git push origin "${TAG}"
tag="${PUBLISH_TAG:-$RELEASE_TAG}"
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
echo "version=${tag#v}" >> "$GITHUB_OUTPUT"

- name: Clean dist directory
run: rm -rf dist
- uses: actions/checkout@v5
with:
ref: ${{ steps.target.outputs.tag }}
# uv build and uv publish execute project and dependency code, and nothing
# here writes to the repository, so do not leave GITHUB_TOKEN in .git/config.
persist-credentials: false

- uses: ./.github/actions/python-uv-setup

- name: Build distributions
run: uv build

- name: Publish to PyPI (Trusted Publishing)
run: uv publish

- name: Create release on GitHub
uses: ncipollo/release-action@v1
with:
tag: ${{ needs.prepare.outputs.tag }}
token: ${{ secrets.GITHUB_TOKEN }}
skipIfReleaseExists: true
body: |
Release v${{ needs.prepare.outputs.version }}

- Bump type: `${{ needs.prepare.outputs.bump }}`
- Previous: `${{ needs.prepare.outputs.previous_version }}`
- Next: `${{ needs.prepare.outputs.version }}`
- Trigger: `${{ github.event_name }}`

Install with: `pip install getstream==${{ needs.prepare.outputs.version }}`

- name: Verify pip install
env:
UV_NO_SOURCES: "1"
run: |
uv pip install "getstream==${{ needs.prepare.outputs.version }}" || \
uv pip install "getstream==${{ steps.target.outputs.version }}" || \
echo "WARNING: pip install verification failed (PyPI index may need a moment to propagate)"
3 changes: 3 additions & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
".": "6.1.0"
}
Loading