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
138 changes: 44 additions & 94 deletions .github/workflows/release-title-edit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ name: Release PR Version

on:
# `edited` is not one of the default pull_request types, but it is the point of this
# workflow: retitling the release PR is how a maintainer picks an exact version. The
# other types keep the consistency check attached to the PR as it evolves.
# workflow: retitling the release PR is how a maintainer picks an exact version, and the
# check has to re-run on the new title. The other types keep the consistency check attached
# to the PR as it evolves.
pull_request:
types: [opened, reopened, edited, synchronize]

# Read-only by default; only the job that pushes the Release-As commit widens this.
# Read-only: the check reads the committed version, and polls the pull request while it waits
# for a re-render.
permissions:
contents: read
pull-requests: read

jobs:
version-consistency:
Expand All @@ -25,30 +28,39 @@ jobs:
# typo'd into the title still reaches the script and fails there, rather than falling out
# of the guard and leaving no check at all — a missing check is not a failing one, and this
# is the check the release PR's footer tells maintainers to wait for before merging.
#
# It is also what keeps the workflow from failing silently if the platform ever opens
# release PRs from a different account: the bridge below stops firing, but this check still
# runs, the retitled version and the committed one disagree, and it turns red. The merge is
# blocked loudly instead of releasing the old version.
if: >-
${{ github.event.pull_request.base.ref == 'main'
&& startsWith(github.event.pull_request.title, 'release: ') }}
runs-on: ubuntu-latest
# Bounds the wait below with room to spare; a re-render normally lands within a minute.
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# The version committed on the PR head is what merging would actually release.
ref: ${{ github.event.pull_request.head.sha }}
# Fails while the title version and the committed version disagree — the window between
# a maintainer's retitle and the platform re-rendering the PR from it. Without this a
# merge in that window would tag a release whose own files self-report the old version,
# and a title release-please cannot parse would silently cut no release at all.
# A retitle is applied by the Scalar platform, which pushes a Release-As commit to the
# integration branch and re-renders the release PR at that version. Until it lands, the
# title and the committed version disagree, and a merge in that window would tag a release
# whose own files self-report the old version.
#
# So this waits rather than failing: the check stays pending, which blocks a merge just as
# a failure would where the check is required, but does not flash red on every retitle. It
# passes once the title and the committed version agree, and hands over once the head
# moves, since the re-render's push starts a run of its own on the new head. It never
# passes while the title still disagrees, even a newer title: the run started for that
# edit judges it, and a pass here would sit beside it on the same head. Only a re-render
# that never arrives, or a title that is not a version at all, fails it.
- name: Compare the title version with the committed version
env:
# The title is human input, so it is bound through the environment (never
# interpolated into the script) and matched against a strict semver pattern
# before it is read.
PR_TITLE: ${{ github.event.pull_request.title }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPOSITORY: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
run: |
pattern='^release: ((0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?)$'
if [[ ! "$PR_TITLE" =~ $pattern ]]; then
Expand All @@ -57,87 +69,25 @@ jobs:
fi
title_version="${BASH_REMATCH[1]}"
manifest_version="$(jq -r '.["."]' .release-please-manifest.json)"
if [[ "$title_version" != "$manifest_version" ]]; then
echo "::error::Release PR title says $title_version but the pull request is versioned $manifest_version. Wait for the release PR to be re-rendered at $title_version before merging."
exit 1
fi
echo "Release PR title and committed version agree on $title_version."
apply-title-version:
name: Apply edited release version
# A human retitle of the open release PR is bridged into the canonical explicit-version
# mechanism (a Release-As commit on scalar-next, which the platform re-renders the
# release PR from). `changes.title` is only set when the title itself changed, and bot
# senders are ignored so the platform's own retitles cannot bounce back into another
# commit.
#
# Both signals are required here, unlike the read-only check above, and each covers what the
# other cannot. The author, because this job pushes with `contents: write` and a title is
# free text — anyone able to open a pull request against main could otherwise
# name a version and have it committed to scalar-next. `user.login` is set by GitHub when
# the pull request is opened and cannot be forged by whoever edits the title afterwards.
# The title, because those accounts open pull requests other than release PRs, and retitling
# one of those must not push a release.
#
# One login per platform deployment, since a repo generated by staging carries staging's
# app. Parenthesised because the group is ANDed with the title clause below: without the
# parens that `&&` would bind to the last login alone, letting the other accounts push a
# release off any title. Listed rather than matched on the shared `scalar-docs` stem — a
# prefix test would also admit any future `scalar-docs-*[bot]`, including someone else's.
if: >-
${{ github.event.action == 'edited'
&& github.event.changes.title != null
&& github.event.sender.type != 'Bot'
&& github.event.pull_request.state == 'open'
&& github.event.pull_request.base.ref == 'main'
&& (github.event.pull_request.user.login == 'scalar-docs[bot]'
|| github.event.pull_request.user.login == 'scalar-docs-staging[bot]'
|| github.event.pull_request.user.login == 'scalar-docs-development[bot]')
&& startsWith(github.event.pull_request.title, 'release: ') }}
# One bridge run at a time per pull request, newest retitle wins. Two retitles in quick
# succession (a version typo corrected seconds later) would otherwise start two runs that
# both read the version committed on the PR head, both get past the no-op guard, and both
# push — and since each fetches scalar-next immediately before committing, the second
# push fast-forwards instead of failing. release-please honours the newest Release-As
# footer, so the release would land on whichever run happened to push last, not on the
# title the maintainer actually left behind.
concurrency:
group: release-title-edit-${{ github.event.pull_request.number }}
cancel-in-progress: true
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# The PR head, so the version the pull request currently carries can be read before
# deciding whether anything needs to change.
ref: ${{ github.event.pull_request.head.sha }}
- name: Push a Release-As commit for the edited version
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
set -euo pipefail
pattern='^release: ((0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?)$'
if [[ ! "$PR_TITLE" =~ $pattern ]]; then
echo "::error::Release PR title must be \"release: X.Y.Z\" with a full semver version, got: $PR_TITLE"
exit 1
fi
# Only ever a validated semver from here on, so it is safe in a commit message.
version="${BASH_REMATCH[1]}"
manifest_version="$(jq -r '.["."]' .release-please-manifest.json)"
# The re-rendered PR is retitled to the version it now carries; stopping here keeps
# that from producing an endless chain of Release-As commits.
if [[ "$version" == "$manifest_version" ]]; then
echo "This release PR already carries $version; nothing to do."
if [[ "$title_version" == "$manifest_version" ]]; then
echo "Release PR title and committed version agree on $title_version."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git fetch origin scalar-next
git checkout -B scalar-next origin/scalar-next
git commit --allow-empty -m "chore: release $version" -m "Release-As: $version"
# Plain (non-force) push: losing a race against a regeneration push fails loudly
# rather than discarding it, and the retitle can simply be repeated.
git push origin scalar-next
echo "Pushed Release-As: $version to scalar-next. The release PR will be re-rendered at that version."
echo "Release PR title says $title_version but the pull request is versioned $manifest_version. Waiting for it to be re-rendered at $title_version."
# Up to ten minutes: 60 polls, 10 seconds apart.
for _ in $(seq 60); do
sleep 10
# A failed read is retried on the next poll rather than failing the check.
current="$(gh api "repos/$REPOSITORY/pulls/$PR_NUMBER" --jq '[.head.sha, .title] | @tsv')" || continue
IFS=$'\t' read -r current_sha current_title <<< "$current"
if [[ "$current_sha" != "$HEAD_SHA" ]]; then
echo "The release PR has a new head; the run for that push checks it."
exit 0
fi
if [[ "$current_title" =~ $pattern && "${BASH_REMATCH[1]}" == "$manifest_version" ]]; then
echo "Release PR title and committed version agree on $manifest_version."
exit 0
fi
done
echo "::error::Release PR title says $title_version but the pull request is still versioned $manifest_version after 10 minutes. Rebuild the SDK from the Scalar dashboard to re-render it."
exit 1
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.3.0"
".": "1.3.2"
}
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Changelog

## [1.3.2](https://github.com/gumlet/python-sdk/compare/v1.3.0...v1.3.2) (2026-10-25)


### ⚠ BREAKING CHANGES

* **api:** 3 breaking changes to the SDK surface.
- Removed operation `folders.deleteAssets` (`POST /video/workspaces/{workspace_id}/remove-assets-from-folder`).
- Removed operation `channelViewers.delete` (`POST /channel/{video_workspace_id}/viewers/remove`).
- Removed operation `videoAnalytics.chartData` (`POST /insights/viewer-analytics`).
* **api:** query param `collection_id` on `videoPlaylists.listAll` is now required.

### Features

* **api:** remove operation folders.deleteAssets (+5 more changes) ([a69343c](https://github.com/gumlet/python-sdk/commit/a69343c1e27cb114ca45dd6d80abb40a46d2c9cf))
* **api:** update SDK surface (2 changes) ([2656fa1](https://github.com/gumlet/python-sdk/commit/2656fa1b5ddd304b8566482f3507a320dbcc4322))


### Chores

* **api:** regenerate SDK ([976363d](https://github.com/gumlet/python-sdk/commit/976363d4fdaed2ace3bf8d7b5df55fee6b0ac53e))
* release 1.3.2 ([e9f52a8](https://github.com/gumlet/python-sdk/commit/e9f52a8c53e295c389d0e9958ae27e32c09bfab9))

## [1.3.0](https://github.com/gumlet/python-sdk/compare/v1.2.2...v1.3.0) (2026-10-22)


Expand Down
7 changes: 4 additions & 3 deletions VERSIONING.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@ not have picked — **edit the release PR title** to the version you want:
release: 1.0.0
```

The `Release PR version` check turns red as soon as you save, because the version in the
The `Release PR version` check goes pending as soon as you save, because the version in the
title no longer matches the version committed in the PR. The Scalar platform then re-renders
the release PR at your version (changelog, manifest, and every version-bearing file), the
title comes back as `release: 1.0.0`, and the check turns green. **Wait for it to be green
before merging** — merging in between would tag a release whose own files still carry the
old version.
old version. The check only turns red if the title is not a full semver version, or if the
re-render has not arrived within 10 minutes.

The git-native equivalent, if you would rather not touch the PR: push an empty commit with a
`Release-As` footer to `scalar-next`. This is exactly what the title edit does for you.
Expand Down Expand Up @@ -95,6 +96,6 @@ Releases work without this; it closes a window where one can go out at the wrong

- **If this repository uses auto-merge, make the `Release PR version` check a required status
check.** Auto-merge merges as soon as the checks that are *required* go green, with no
human present — so a check that is not required but still red at that moment stops
human present — so a check that is not required but still pending at that moment stops
nothing, which is exactly the window between retitling a release PR and the platform
re-rendering it.
26 changes: 14 additions & 12 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,9 @@ Get all playlists for given workspace
| Response | [`VideoPlaylistListAllResponse`](./src/gumlet/types/video_playlist_list_all_response.py) |

```python
video_playlist = client.video_playlists.list_all()
video_playlist = client.video_playlists.list_all(
collection_id="collection_id",
)
```

### Add asset to playlist
Expand Down Expand Up @@ -1201,9 +1203,9 @@ Video workspaces are top-level entities in Gumlet. You can use them to organize

```python
video_workspace = client.video_workspaces.create(
name="zoom-workspace",
name="My Workspace",
type="direct-upload",
zoom={"secret": "yourSecret"},
data_localization="us",
)
```

Expand Down Expand Up @@ -1348,11 +1350,11 @@ Remove one or more assets from their current folder assignment inside the worksp

| Direction | Type |
| --- | --- |
| Request | [`FolderDeleteAssetsParams`](./src/gumlet/types/folder_delete_assets_params.py) |
| Response | [`FolderDeleteAssetsResponse`](./src/gumlet/types/folder_delete_assets_response.py) |
| Request | [`FolderRemoveAssetsParams`](./src/gumlet/types/folder_remove_assets_params.py) |
| Response | [`FolderRemoveAssetsResponse`](./src/gumlet/types/folder_remove_assets_response.py) |

```python
folder = client.folders.delete_assets(
folder = client.folders.remove_assets(
workspace_id="workspaceId",
asset_ids=["67e4f2b4403562dbea654301", "67e4f2bb403562dbea654302"],
)
Expand Down Expand Up @@ -1388,11 +1390,11 @@ Remove one or more viewers from a channel by email address.

| Direction | Type |
| --- | --- |
| Request | [`ChannelViewerDeleteParams`](./src/gumlet/types/channel_viewer_delete_params.py) |
| Response | [`ChannelViewerDeleteResponse`](./src/gumlet/types/channel_viewer_delete_response.py) |
| Request | [`ChannelViewerRemoveParams`](./src/gumlet/types/channel_viewer_remove_params.py) |
| Response | [`ChannelViewerRemoveResponse`](./src/gumlet/types/channel_viewer_remove_response.py) |

```python
channel_viewer = client.channel_viewers.delete(
channel_viewer = client.channel_viewers.remove(
video_workspace_id="videoWorkspaceId",
emails=["test@gumlet.com", "test+2@gumlet.com"],
)
Expand Down Expand Up @@ -1441,11 +1443,11 @@ This endpoint retrieves viewer analytics data. This endpoint is use for deep ins

| Direction | Type |
| --- | --- |
| Request | [`VideoAnalyticChartDataParams`](./src/gumlet/types/video_analytic_chart_data_params.py) |
| Response | [`VideoAnalyticChartDataResponse`](./src/gumlet/types/video_analytic_chart_data_response.py) |
| Request | [`VideoAnalyticViewerDataParams`](./src/gumlet/types/video_analytic_viewer_data_params.py) |
| Response | [`VideoAnalyticViewerDataResponse`](./src/gumlet/types/video_analytic_viewer_data_response.py) |

```python
video_analytic = client.video_analytics.chart_data(
video_analytic = client.video_analytics.viewer_data(
metrics=["views"],
date_range={"start_at": "2024-01-01", "end_at": "2024-01-01"},
group_by="daily",
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "gumlet"
version = "1.3.0" # x-release-please-version
version = "1.3.2" # x-release-please-version
description = "Gumlet helps developers deliver online video and images. This API encompasses Gumlet Video, Image and Video Analytics functionality to help you build your products better and faster than ever before."
readme = "README.md"
license = "Apache-2.0"
Expand Down
Loading
Loading