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
5 changes: 5 additions & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
paths:
.github/workflows/release.yml:
ignore:
# GitHub supports concurrency.queue, but actionlint 1.7.12 does not know it yet.
- 'unexpected key "queue" for "concurrency" section'
6 changes: 3 additions & 3 deletions .github/scripts/release-source.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ if ! git check-ref-format "refs/tags/$RELEASE_TAG"; then
echo "Invalid release tag" >&2
exit 1
fi
if [[ "$GITHUB_EVENT_NAME" != "release" && "$GITHUB_EVENT_NAME" != "workflow_dispatch" ]]; then
if [[ "$GITHUB_EVENT_NAME" != "push" && "$GITHUB_EVENT_NAME" != "workflow_dispatch" ]]; then
echo "Unsupported release event" >&2
exit 1
fi
Expand Down Expand Up @@ -58,8 +58,8 @@ if [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]]; then
exit 0
fi

if [[ "$GITHUB_REF" != "refs/tags/$RELEASE_TAG" ]]; then
echo "Package publication must run from a release tag" >&2
if [[ "$GITHUB_REF" != "refs/heads/main" ]]; then
echo "Package publication must run from main" >&2
exit 1
fi
if [[ "$tag_sha" != "$GITHUB_SHA" || "$head_sha" != "$GITHUB_SHA" ]]; then
Expand Down
154 changes: 140 additions & 14 deletions .github/scripts/release_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,19 @@ extract_run() {
' "$root/.github/workflows/release.yml"
}

[[ "$(run_source release refs/tags/mcp-v0.1.1 "$release_sha")" == "$release_sha" ]]
expect_failure "Package publication must run from a release tag" \
run_source release refs/heads/main "$release_sha"
[[ "$(run_source push refs/heads/main "$release_sha")" == "$release_sha" ]]
expect_failure "Package publication must run from main" \
run_source push refs/tags/mcp-v0.1.1 "$release_sha"
expect_failure "Release tag, event, and checkout commits do not match" \
run_source release refs/tags/mcp-v0.1.1 deadbeef
run_source push refs/heads/main deadbeef
expect_failure "Unsupported release event" \
run_source push refs/tags/mcp-v0.1.1 "$release_sha"
run_source release refs/tags/mcp-v0.1.1 "$release_sha"
expect_failure "Invalid release tag" \
run_source release 'refs/tags/mcp-v0.1.1^{}' "$release_sha" 'mcp-v0.1.1^{}'
run_source push refs/heads/main "$release_sha" 'mcp-v0.1.1^{}'
expect_failure "Invalid release tag" \
run_source release 'refs/tags/../main' "$release_sha" '../main'
run_source push refs/heads/main "$release_sha" '../main'
git -C "$repo" tag --annotate annotated-v0.1.1 --message release
[[ "$(run_source release refs/tags/annotated-v0.1.1 "$release_sha" annotated-v0.1.1)" == "$release_sha" ]]
[[ "$(run_source push refs/heads/main "$release_sha" annotated-v0.1.1)" == "$release_sha" ]]

printf '{"name":"repo","packageManager":"pnpm@11.25.0"}\n' > "$repo/package.json"
printf 'name: CI\n' > "$repo/.github/workflows/ci.yml"
Expand All @@ -100,9 +100,9 @@ extract_run discover-release > "$tmp/discover.sh"
run_discovery() {
(
cd "$repo"
PATH="$tmp/bin:$PATH" DRAFT="$1" RELEASE_TAG="${2:-mcp-v0.1.1}" \
PATH="$tmp/bin:$PATH" DRAFT="$1" RELEASE_TAG="${2:-mcp-v0.1.1}" RELEASED_PATHS='[]' \
GITHUB_REPOSITORY=telemetry-dev/sdks GITHUB_EVENT_NAME=workflow_dispatch \
GITHUB_REF=refs/heads/main GITHUB_SHA="$recovery_sha" GITHUB_OUTPUT="$tmp/output" \
GITHUB_REF=refs/heads/main GITHUB_SHA="${3:-$recovery_sha}" GITHUB_OUTPUT="$tmp/output" \
bash -eo pipefail "$tmp/discover.sh"
)
}
Expand All @@ -117,6 +117,44 @@ git -C "$repo" tag python-v0.2.2 "$release_sha"
run_discovery false python-v0.2.2
grep -Fxq 'python=["sdks/python"]' "$tmp/output"

git -C "$repo" switch --quiet --detach "$recovery_sha"
printf '{"packages/otel":"0.1.0","packages/mcp":"0.1.2","sdks/python":"0.2.3"}\n' > "$repo/.release-please-manifest.json"
jq '.packages = ({"packages/otel": {"component": "otel", "release-type": "node"}} + .packages)' \
"$repo/release-please-config.json" > "$repo/release-please-config.json.next"
mv "$repo/release-please-config.json.next" "$repo/release-please-config.json"
git -C "$repo" commit --quiet --all -m release-batch
batch_sha=$(git -C "$repo" rev-parse HEAD)
for tag in otel-v0.1.0 mcp-v0.1.2 python-v0.2.3; do
git -C "$repo" tag "$tag"
done
run_push_discovery() {
(
cd "$repo"
rm -f "$tmp/output"
PATH="$tmp/bin:$PATH" DRAFT="$1" RELEASED_PATHS="$2" RELEASE_TAG='' \
GITHUB_REPOSITORY=telemetry-dev/sdks GITHUB_EVENT_NAME=push \
GITHUB_REF=refs/heads/main GITHUB_SHA="${3:-$batch_sha}" GITHUB_OUTPUT="$tmp/output" \
bash -eo pipefail "$tmp/discover.sh"
)
}
for released in '["sdks/python","packages/mcp","packages/otel"]' '["packages/mcp"]' '[]'; do
run_push_discovery false "$released"
grep -Fxq 'npm=["packages/otel","packages/mcp"]' "$tmp/output"
grep -Fxq 'python=["sdks/python"]' "$tmp/output"
grep -Fxq "sha=$batch_sha" "$tmp/output"
done
run_push_discovery false '[]' "$recovery_sha"
grep -Fxq 'npm=[]' "$tmp/output"
grep -Fxq 'python=[]' "$tmp/output"
expect_failure "Expected 2 configured packages for released paths, found 1" \
run_push_discovery false '["packages/mcp","packages/unknown"]'
expect_failure "Release otel-v0.1.0 is still a draft" run_push_discovery true '["packages/otel"]'
expect_failure "Release tag, event, and checkout commits do not match" \
run_push_discovery false '["packages/otel"]' "$release_sha"
git -C "$repo" commit --quiet --allow-empty -m after-batch
expect_failure "Release tag, event, and checkout commits do not match" \
run_push_discovery false '["packages/otel"]' "$(git -C "$repo" rev-parse HEAD)"

release_tree=$(git -C "$repo" show --no-patch --format=%T "$release_sha")
unrelated_sha=$(printf 'unrelated\n' | git -C "$repo" commit-tree "$release_tree")
git -C "$repo" switch --quiet --detach "$unrelated_sha"
Expand All @@ -130,6 +168,8 @@ git -C "$repo" commit --quiet -m source-change
source_change_sha=$(git -C "$repo" rev-parse HEAD)
expect_failure "Retry commit changes release source files" \
run_source workflow_dispatch refs/heads/main "$source_change_sha"
expect_failure "Retry commit changes release source files" \
run_discovery false mcp-v0.1.1 "$source_change_sha"

for path in scripts/package-exports.mjs sdks/python/pyproject.toml pnpm-lock.yaml; do
git -C "$repo" switch --quiet --detach "$recovery_sha"
Expand Down Expand Up @@ -217,15 +257,52 @@ for field in dependencies peerDependencies; do
[[ ! -e "$tmp/published" && ! -e "$tmp/attempts" ]]
expect_failure 'Integrity mismatch' run_publish sha512-wrong true
expect_failure 'unable to verify that published @telemetry-dev/sdk satisfies ^0.1.1' run_publish '' false
[[ ! -e "$tmp/published" && $(wc -l < "$tmp/attempts") -eq 12 ]]
[[ ! -e "$tmp/published" && $(wc -l < "$tmp/attempts") -eq 60 ]]
run_publish '' true
[[ $(wc -l < "$tmp/published") -eq 1 && $(wc -l < "$tmp/attempts") -eq 13 ]]
[[ $(wc -l < "$tmp/published") -eq 1 && $(wc -l < "$tmp/attempts") -eq 61 ]]
if grep -Fq '@telemetry-dev-extra/helper' "$tmp/queries"; then
echo "Unexpected registry query for namespace near-miss in $field" >&2
exit 1
fi
done

mkdir -p "$tmp/python-publish/.github/scripts" "$tmp/python-publish/python/python" \
"$tmp/python-publish/python/python-anthropic" "$tmp/python-bin"
touch "$tmp/python-publish/python/python/telemetry_dev-0.2.3-py3-none-any.whl" \
"$tmp/python-publish/python/python-anthropic/telemetry_dev_anthropic-0.1.4-py3-none-any.whl"
printf 'python\npython-anthropic\n' > "$tmp/python-publish/python/publish-order.txt"
cat > "$tmp/python-publish/.github/scripts/verify-python-release-dependencies.sh" <<'SH'
#!/usr/bin/env bash
printf 'verify %s\n' "$1" >> "$PYTHON_LOG"
[[ "$1" != *anthropic* || "$ANTHROPIC_DEPENDENCIES_AVAILABLE" == true ]] || {
echo 'anthropic dependencies unavailable' >&2
exit 1
}
SH
cat > "$tmp/python-bin/uv" <<'SH'
#!/usr/bin/env bash
printf 'uv %s\n' "$*" >> "$PYTHON_LOG"
SH
chmod +x "$tmp/python-publish/.github/scripts/verify-python-release-dependencies.sh" "$tmp/python-bin/uv"
extract_run publish-python > "$tmp/publish-python.sh"
run_python_publish() {
(
cd "$tmp/python-publish"
rm -f "$tmp/python-log"
PATH="$tmp/python-bin:$PATH" PYTHON_LOG="$tmp/python-log" ANTHROPIC_DEPENDENCIES_AVAILABLE="$1" \
bash -eo pipefail "$tmp/publish-python.sh"
)
}
uv_publish='uv publish --trusted-publishing always --check-url https://pypi.org/simple'
core_log="verify python/python/telemetry_dev-0.2.3-py3-none-any.whl
$uv_publish python/python/telemetry_dev-0.2.3-py3-none-any.whl
verify python/python-anthropic/telemetry_dev_anthropic-0.1.4-py3-none-any.whl"
run_python_publish true
[[ "$(cat "$tmp/python-log")" == "$core_log
$uv_publish python/python-anthropic/telemetry_dev_anthropic-0.1.4-py3-none-any.whl" ]]
expect_failure 'anthropic dependencies unavailable' run_python_publish false
[[ "$(cat "$tmp/python-log")" == "$core_log" ]]

touch "$tmp/provider.whl"
cat > "$tmp/bin/uv" <<'SH'
#!/usr/bin/env bash
Expand Down Expand Up @@ -332,9 +409,58 @@ workflow_pnpm=$(
' "$root/.github/workflows/release.yml"
)
[[ "$workflow_pnpm" == "$package_pnpm" ]]
[[ $(grep -Ec '^[[:space:]]*concurrency:' "$root/.github/workflows/release.yml") -eq 1 ]]
grep -Fxq " group: release-\${{ github.event.release.tag_name || inputs.release_tag || github.ref }}" \
[[ $(grep -Ec '^[[:space:]]*concurrency:' "$root/.github/workflows/release.yml") -eq 2 ]]
grep -Fxq " group: release-\${{ inputs.release_tag || github.sha }}" \
"$root/.github/workflows/release.yml"
grep -Fxq " group: release-please-\${{ github.ref }}" \
"$root/.github/workflows/release.yml"
grep -Fxq " !cancelled() && (github.event_name == 'workflow_dispatch' ||" \
"$root/.github/workflows/release.yml"
grep -Fxq " needs.release-please.result == 'success')" \
"$root/.github/workflows/release.yml"
grep -Fxq " queue: max" "$root/.github/workflows/release.yml"
[[ $(grep -Fxc " !cancelled() && needs.discover-release.result == 'success' &&" \
"$root/.github/workflows/release.yml") -eq 2 ]]
for job in npm python; do
grep -Fxq " if: \"!cancelled() && needs.build-$job.result == 'success'\"" \
"$root/.github/workflows/release.yml"
done
grep -Fxq " RELEASE_DEPENDENCY_ATTEMPTS: 60" "$root/.github/workflows/release.yml"
python3 - "$root" <<'PY'
import json
import pathlib
import re
import sys
import tomllib

root = pathlib.Path(sys.argv[1])
packages = json.loads((root / "release-please-config.json").read_text())["packages"]
order = list(packages)


def normalize(name):
return re.sub(r"[-_.]+", "-", name).lower()


paths = {}
dependencies = {}
for path, package in packages.items():
if package["release-type"] == "node":
manifest = json.loads((root / path / "package.json").read_text())
paths[manifest["name"]] = path
dependencies[path] = [*manifest.get("dependencies", {}), *manifest.get("peerDependencies", {})]
else:
project = tomllib.loads((root / path / "pyproject.toml").read_text())["project"]
paths[normalize(project["name"])] = path
dependencies[path] = [
normalize(re.match(r"[A-Za-z0-9._-]+", requirement)[0]) for requirement in project.get("dependencies", [])
]
for path in order:
for dependency in dependencies[path]:
dependency_path = paths.get(dependency)
if dependency_path and order.index(dependency_path) > order.index(path):
sys.exit(f"release-please-config.json lists {path} before its dependency {dependency_path}")
PY
grep -Fxq " NPM_CONFIG_PROVENANCE: \${{ github.event.repository.private && 'false' || 'true' }}" \
"$root/.github/workflows/release.yml"
grep -Fxq " npm publish \"./npm/\$tarball\" --access public" \
Expand Down
Loading
Loading