Skip to content

Commit b6be9bd

Browse files
updates
1 parent 34978fc commit b6be9bd

4 files changed

Lines changed: 143 additions & 160 deletions

File tree

‎docs/tools.md‎

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -163,27 +163,31 @@ For details on the Doxygen configuration and CI pipeline, see the
163163

164164
### Bump the pinned Rust submodule
165165

166-
Update to the commit from the most recent published Rust SDK release:
166+
Update to the commit from the Rust SDK release with the newest publication
167+
time (including prereleases, excluding drafts):
167168

168169
```bash
169170
./scripts/update-rust-sdk.sh
170171
```
171172

172-
The script requires the GitHub CLI (`gh`) when `--hash` is omitted. To select a
173-
specific commit without `gh`, pass its full or abbreviated hash:
173+
The script requires an authenticated GitHub CLI (`gh auth login`, or `GH_TOKEN`)
174+
when `--hash` is omitted. To select a specific commit without `gh`, pass its full
175+
or abbreviated hash:
174176

175177
```bash
176178
./scripts/update-rust-sdk.sh --hash 1a477bc
177179
```
178180

179-
The script updates the `client-sdk-rust` gitlink and synchronizes its nested
180-
submodules. It stops without changing the checkout if the Rust submodule has
181-
tracked changes.
181+
The script checks out the selected Rust commit and synchronizes its nested
182+
submodules. It leaves the parent index untouched; review and stage the gitlink
183+
when ready. `--hash` also permits unreleased commits for local development; CI
184+
requires a published release for the pinned Rust commit.
182185

183186
Review the selected commits before committing the gitlink update:
184187

185188
```bash
186-
git submodule status --recursive
189+
git diff --submodule=log -- client-sdk-rust
190+
git add -- client-sdk-rust
187191
```
188192

189193
### Bump the pinned C++ example collection
@@ -201,9 +205,16 @@ To select a specific commit, pass its full or abbreviated hash:
201205
./scripts/update-cpp-example-collection.sh --hash 7e76bea
202206
```
203207

204-
The script updates the `cpp-example-collection` gitlink and synchronizes its
205-
nested submodules. It stops without changing the checkout if the examples
206-
submodule has tracked changes.
208+
Review and stage the examples gitlink when ready:
209+
210+
```bash
211+
git diff --submodule=log -- cpp-example-collection
212+
git add -- cpp-example-collection
213+
```
214+
215+
Both updaters run from any working directory, initialize the selected submodule
216+
if necessary, detach its checkout at the selected commit, and synchronize nested
217+
submodules using checkout mode.
207218

208219
### If `yuv-sys` fails to build
209220

‎scripts/update-cpp-example-collection.sh‎

Lines changed: 6 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ set -euo pipefail
1818

1919
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
2020
repo_root="$(cd "${script_dir}/.." && pwd -P)"
21-
examples_dir="${repo_root}/cpp-example-collection"
2221
examples_repo="livekit-examples/cpp-example-collection"
2322
examples_remote="https://github.com/${examples_repo}.git"
2423
default_branch="main"
@@ -78,71 +77,12 @@ if [[ "$hash_provided" == true && ! "$requested_hash" =~ ^[0-9a-fA-F]{7,40}$ ]];
7877
exit 2
7978
fi
8079

81-
if ! command -v git >/dev/null 2>&1; then
82-
echo "ERROR: git not found in PATH" >&2
83-
exit 1
84-
fi
85-
86-
if ! git -C "$repo_root" rev-parse --show-toplevel >/dev/null 2>&1; then
87-
echo "ERROR: ${repo_root} is not a Git worktree" >&2
88-
exit 1
89-
fi
90-
91-
if [[ ! -e "${examples_dir}/.git" ]]; then
92-
echo "==> Initializing cpp-example-collection"
93-
git -C "$repo_root" submodule update --init cpp-example-collection
94-
fi
95-
96-
if ! git -C "$examples_dir" diff --quiet ||
97-
! git -C "$examples_dir" diff --cached --quiet; then
98-
echo "ERROR: cpp-example-collection has tracked changes; commit or stash them first" >&2
99-
exit 1
100-
fi
101-
102-
fetch_ref="$requested_hash"
80+
# Shared checkout logic keeps the two dependency updaters consistent.
81+
source "${script_dir}/update-submodule-common.sh"
82+
check_update_prerequisites
10383

84+
fetch_ref=""
10485
if [[ "$hash_provided" == false ]]; then
105-
echo "==> Finding the most recent cpp-example-collection commit"
106-
branch_ref="refs/heads/${default_branch}"
107-
remote_ref="$(git ls-remote "$examples_remote" "$branch_ref")"
108-
read -r requested_hash resolved_ref <<<"$remote_ref"
109-
if [[ -z "$requested_hash" || "$resolved_ref" != "$branch_ref" ]]; then
110-
echo "ERROR: branch '${default_branch}' was not found in ${examples_repo}" >&2
111-
exit 1
112-
fi
113-
fetch_ref="$branch_ref"
114-
echo "==> Latest ${default_branch} commit: ${requested_hash}"
115-
else
116-
requested_hash="$(printf '%s' "$requested_hash" | tr '[:upper:]' '[:lower:]')"
117-
echo "==> Requested examples commit: ${requested_hash}"
86+
fetch_ref="refs/heads/${default_branch}"
11887
fi
119-
120-
echo "==> Fetching cpp-example-collection"
121-
if [[ "$hash_provided" == false ]]; then
122-
git -C "$examples_dir" fetch --quiet origin "$fetch_ref"
123-
elif [[ ${#requested_hash} -eq 40 ]]; then
124-
if ! git -C "$examples_dir" fetch --quiet origin "$fetch_ref"; then
125-
git -C "$examples_dir" fetch --quiet origin
126-
fi
127-
else
128-
git -C "$examples_dir" fetch --quiet origin
129-
fi
130-
131-
if ! resolved_hash="$(git -C "$examples_dir" rev-parse --verify "${requested_hash}^{commit}" 2>/dev/null)"; then
132-
echo "ERROR: '${requested_hash}' does not resolve to a cpp-example-collection commit" >&2
133-
exit 1
134-
fi
135-
136-
current_hash="$(git -C "$examples_dir" rev-parse HEAD)"
137-
if [[ "$current_hash" == "$resolved_hash" ]]; then
138-
echo "==> cpp-example-collection is already at ${resolved_hash}"
139-
else
140-
git -C "$examples_dir" checkout --quiet --detach "$resolved_hash"
141-
echo "==> Updated cpp-example-collection: ${current_hash} -> ${resolved_hash}"
142-
fi
143-
144-
echo "==> Synchronizing nested example submodules"
145-
git -C "$examples_dir" submodule sync --recursive
146-
git -C "$examples_dir" submodule update --init --recursive
147-
148-
echo "==> Done. Review and commit the cpp-example-collection gitlink change."
88+
update_submodule cpp-example-collection "$examples_remote" "$fetch_ref"

‎scripts/update-rust-sdk.sh‎

Lines changed: 17 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ set -euo pipefail
1818

1919
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
2020
repo_root="$(cd "${script_dir}/.." && pwd -P)"
21-
rust_dir="${repo_root}/client-sdk-rust"
2221
rust_repo="livekit/client-sdk-rust"
2322
rust_remote="https://github.com/${rust_repo}.git"
2423

@@ -35,8 +34,9 @@ Options:
3534
-h, --help
3635
Show this help and exit.
3736
38-
When --hash is omitted, the script uses the commit tagged by the most recent
39-
published, non-draft GitHub release in livekit/client-sdk-rust (requires gh).
37+
When --hash is omitted, the script uses the commit tagged by the most recently
38+
published, non-draft GitHub release (including prereleases) in
39+
livekit/client-sdk-rust (requires gh).
4040
EOF
4141
}
4242

@@ -77,98 +77,31 @@ if [[ "$hash_provided" == true && ! "$requested_hash" =~ ^[0-9a-fA-F]{7,40}$ ]];
7777
exit 2
7878
fi
7979

80-
if ! command -v git >/dev/null 2>&1; then
81-
echo "ERROR: git not found in PATH" >&2
82-
exit 1
83-
fi
84-
85-
if ! git -C "$repo_root" rev-parse --show-toplevel >/dev/null 2>&1; then
86-
echo "ERROR: ${repo_root} is not a Git worktree" >&2
87-
exit 1
88-
fi
89-
90-
if [[ ! -e "${rust_dir}/.git" ]]; then
91-
echo "==> Initializing client-sdk-rust"
92-
git -C "$repo_root" submodule update --init client-sdk-rust
93-
fi
94-
95-
if ! git -C "$rust_dir" diff --quiet ||
96-
! git -C "$rust_dir" diff --cached --quiet; then
97-
echo "ERROR: client-sdk-rust has tracked changes; commit or stash them first" >&2
98-
exit 1
99-
fi
100-
101-
fetch_ref="$requested_hash"
102-
release_tag=""
80+
# Shared checkout logic keeps the two dependency updaters consistent.
81+
source "${script_dir}/update-submodule-common.sh"
82+
check_update_prerequisites
10383

10484
if [[ "$hash_provided" == false ]]; then
10585
if ! command -v gh >/dev/null 2>&1; then
10686
echo "ERROR: gh not found in PATH; install GitHub CLI or provide --hash" >&2
10787
exit 1
10888
fi
109-
110-
echo "==> Finding the most recent published Rust SDK release"
111-
release_tags="$(
112-
gh api --paginate "repos/${rust_repo}/releases?per_page=100" \
113-
--jq '.[] | select(.draft == false) | .tag_name'
114-
)"
115-
release_tag="${release_tags%%$'\n'*}"
89+
echo "==> Finding the most recently published Rust SDK release"
90+
# Sort across every page by publication time, including prereleases. API
91+
# list order and GitHub's designated "latest" release are different concepts.
92+
release_tag="$(gh api --hostname github.com --paginate --slurp \
93+
"repos/${rust_repo}/releases?per_page=100" \
94+
--jq '[.[][] | select(.draft == false and .published_at != null)] |
95+
sort_by(.published_at, .id) | last | .tag_name // empty')"
11696
if [[ -z "$release_tag" ]]; then
11797
echo "ERROR: no published release found for ${rust_repo}" >&2
11898
exit 1
11999
fi
120-
121-
tag_refs="$(
122-
git ls-remote "$rust_remote" \
123-
"refs/tags/${release_tag}" "refs/tags/${release_tag}^{}"
124-
)"
125-
while read -r tag_hash tag_ref; do
126-
if [[ "$tag_ref" == "refs/tags/${release_tag}^{}" ]]; then
127-
requested_hash="$tag_hash"
128-
break
129-
fi
130-
if [[ "$tag_ref" == "refs/tags/${release_tag}" ]]; then
131-
requested_hash="$tag_hash"
132-
fi
133-
done <<<"$tag_refs"
134-
135-
if [[ -z "$requested_hash" ]]; then
136-
echo "ERROR: release tag '${release_tag}' was not found in ${rust_repo}" >&2
137-
exit 1
138-
fi
100+
git check-ref-format "refs/tags/${release_tag}" >/dev/null
139101
fetch_ref="refs/tags/${release_tag}"
140-
echo "==> Latest release: ${release_tag} (${requested_hash})"
141-
else
142-
requested_hash="$(printf '%s' "$requested_hash" | tr '[:upper:]' '[:lower:]')"
143-
echo "==> Requested Rust SDK commit: ${requested_hash}"
144-
fi
145-
146-
echo "==> Fetching client-sdk-rust"
147-
if [[ "$hash_provided" == false ]]; then
148-
git -C "$rust_dir" fetch --quiet origin "$fetch_ref"
149-
elif [[ ${#requested_hash} -eq 40 ]]; then
150-
if ! git -C "$rust_dir" fetch --quiet origin "$fetch_ref"; then
151-
git -C "$rust_dir" fetch --quiet origin
152-
fi
102+
echo "==> Selected release: ${release_tag}"
153103
else
154-
git -C "$rust_dir" fetch --quiet origin
104+
fetch_ref=""
155105
fi
156106

157-
if ! resolved_hash="$(git -C "$rust_dir" rev-parse --verify "${requested_hash}^{commit}" 2>/dev/null)"; then
158-
echo "ERROR: '${requested_hash}' does not resolve to a client-sdk-rust commit" >&2
159-
exit 1
160-
fi
161-
162-
current_hash="$(git -C "$rust_dir" rev-parse HEAD)"
163-
if [[ "$current_hash" == "$resolved_hash" ]]; then
164-
echo "==> client-sdk-rust is already at ${resolved_hash}"
165-
else
166-
git -C "$rust_dir" checkout --quiet --detach "$resolved_hash"
167-
echo "==> Updated client-sdk-rust: ${current_hash} -> ${resolved_hash}"
168-
fi
169-
170-
echo "==> Synchronizing nested Rust SDK submodules"
171-
git -C "$rust_dir" submodule sync --recursive
172-
git -C "$rust_dir" submodule update --init --recursive --checkout
173-
174-
echo "==> Done. Review and commit the client-sdk-rust gitlink change."
107+
update_submodule client-sdk-rust "$rust_remote" "$fetch_ref"

‎scripts/update-submodule-common.sh‎

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Copyright 2026 LiveKit
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
# Internal helpers sourced by update-rust-sdk.sh and
18+
# update-cpp-example-collection.sh. Requires Bash 3.2 or newer.
19+
20+
check_update_prerequisites() {
21+
if ! command -v git >/dev/null 2>&1; then
22+
echo "ERROR: git not found in PATH" >&2
23+
exit 1
24+
fi
25+
local top_level
26+
top_level="$(git -C "$repo_root" rev-parse --show-toplevel)"
27+
if [[ "$(cd "$top_level" && pwd -P)" != "$repo_root" ]]; then
28+
echo "ERROR: ${repo_root} is not the SDK Git worktree root" >&2
29+
exit 1
30+
fi
31+
}
32+
33+
require_clean_submodule() {
34+
local directory="$1"
35+
local changes
36+
# Explicitly override submodule.*.ignore and diff.ignoreSubmodules. This
37+
# includes nested HEAD changes, staged edits, and untracked files.
38+
changes="$(git -C "$directory" status --porcelain --untracked-files=all \
39+
--ignore-submodules=none)"
40+
if [[ -n "$changes" ]]; then
41+
echo "ERROR: ${directory} has local changes (possibly in nested submodules)." >&2
42+
echo "Commit, stash, or move them before updating:" >&2
43+
printf '%s\n' "$changes" >&2
44+
exit 1
45+
fi
46+
}
47+
48+
update_submodule() {
49+
local name="$1" remote="$2" fetch_ref="$3"
50+
local directory="${repo_root}/${name}"
51+
local resolved_hash current_hash
52+
local fetch_options=(--no-tags)
53+
54+
if [[ -e "${directory}/.git" ]]; then
55+
require_clean_submodule "$directory"
56+
else
57+
echo "==> Initializing ${name}"
58+
git -C "$repo_root" submodule update --init --checkout -- "$name"
59+
require_clean_submodule "$directory"
60+
fi
61+
62+
echo "==> Fetching ${name} from ${remote}"
63+
# Use the same authoritative repository for resolution and fetching, even
64+
# when a developer's origin points to a fork. Leave their remotes unchanged.
65+
if [[ "$hash_provided" == false ]]; then
66+
git -C "$directory" fetch --quiet --no-tags "$remote" "$fetch_ref"
67+
resolved_hash="$(git -C "$directory" rev-parse --verify 'FETCH_HEAD^{commit}')"
68+
else
69+
requested_hash="$(printf '%s' "$requested_hash" | tr '[:upper:]' '[:lower:]')"
70+
if [[ ${#requested_hash} -lt 40 ]] ||
71+
! git -C "$directory" fetch --quiet --no-tags "$remote" "$requested_hash"; then
72+
# Abbreviated hashes cannot be fetched directly. Fetch all branch/tag
73+
# objects without updating local branches or overwriting local tags.
74+
if [[ "$(git -C "$directory" rev-parse --is-shallow-repository)" == true ]]; then
75+
fetch_options+=(--unshallow)
76+
fi
77+
git -C "$directory" fetch --quiet "${fetch_options[@]}" "$remote" \
78+
'+refs/heads/*:refs/sdk-update/heads/*' '+refs/tags/*:refs/sdk-update/tags/*'
79+
fi
80+
if ! resolved_hash="$(git -C "$directory" rev-parse --verify "${requested_hash}^{commit}" 2>/dev/null)" ||
81+
[[ "$resolved_hash" != "$requested_hash"* ]]; then
82+
echo "ERROR: '${requested_hash}' does not unambiguously identify a ${name} commit" >&2
83+
exit 1
84+
fi
85+
fi
86+
87+
current_hash="$(git -C "$directory" rev-parse HEAD)"
88+
echo "==> Selected ${name}: ${current_hash} -> ${resolved_hash}"
89+
# Failures here can leave a partial update. Do not attempt a destructive
90+
# rollback; show the developer exactly what needs inspection and retrying.
91+
trap 'echo "ERROR: Update incomplete. Inspect git status and git submodule status --recursive; fix the error and rerun the updater. No changes were staged or committed." >&2' ERR
92+
git -C "$directory" checkout --quiet --no-overwrite-ignore --detach "$resolved_hash"
93+
git -C "$directory" submodule sync --recursive
94+
git -C "$directory" submodule update --init --recursive --checkout
95+
trap - ERR
96+
97+
echo "==> Done. Review with: git diff --submodule=log -- ${name}"
98+
echo "==> Stage when ready: git add -- ${name}"
99+
}

0 commit comments

Comments
 (0)