From b97f8420a2dd6378bd2044a041bbfbe893895a10 Mon Sep 17 00:00:00 2001 From: dielduarte Date: Mon, 13 Jul 2026 16:03:03 -0300 Subject: [PATCH 1/2] chore: add release smoke-test script --- scripts/smoke_test_release.sh | 154 ++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100755 scripts/smoke_test_release.sh diff --git a/scripts/smoke_test_release.sh b/scripts/smoke_test_release.sh new file mode 100755 index 0000000..f0ffeb6 --- /dev/null +++ b/scripts/smoke_test_release.sh @@ -0,0 +1,154 @@ +#!/usr/bin/env bash +# +# smoke_test_release.sh +# +# Smoke-test a released version of the resend Python SDK in a clean, isolated +# Docker container, the way we validate releases: +# +# 1. spin up a fresh python image (nothing pre-installed) +# 2. `pip install resend==` straight from PyPI (as a customer would) +# 3. run a handful of sending-related examples/ files against a real API key +# +# The examples/ folder doubles as our quick smoke-test suite. We don't run all +# of them — just the sending-focused ones (simple_email, attachments, batch...). +# +# Usage: +# ./scripts/smoke_test_release.sh [example ...] +# +# Examples: +# ./scripts/smoke_test_release.sh 2.33.0 re_xxxxxxxx +# ./scripts/smoke_test_release.sh 2.33.0 re_xxxxxxxx simple_email with_attachments +# +# Notes: +# - args are bare names, without the examples/ prefix or .py suffix. +# - The container is --rm (removed on exit); nothing is installed on your host. +# - Exit code is non-zero if any example fails, so it's CI-friendly. + +set -euo pipefail + +# --- args ------------------------------------------------------------------- + +if [[ $# -lt 2 ]]; then + echo "Usage: $0 [example ...]" >&2 + echo " e.g. $0 2.33.0 re_xxxxxxxx simple_email with_attachments" >&2 + exit 1 +fi + +VERSION="$1" +API_KEY="$2" +shift 2 + +# --- preflight: check host dependencies ------------------------------------- +# +# Docker is the only thing this script needs on the host — the SDK, Python and +# everything else live inside the container. Fail fast with a clear message +# instead of a cryptic error mid-run. + +missing_deps=0 + +if ! command -v docker >/dev/null 2>&1; then + echo "Error: 'docker' is not installed or not on your PATH." >&2 + echo " Install Docker Desktop: https://docs.docker.com/get-docker/" >&2 + missing_deps=1 +elif ! docker info >/dev/null 2>&1; then + echo "Error: Docker is installed but the daemon isn't running." >&2 + echo " Start Docker Desktop (or the docker service) and try again." >&2 + missing_deps=1 +fi + +if [[ $missing_deps -ne 0 ]]; then + exit 1 +fi + +# Default sending-focused smoke set. Override by passing example names as args. +if [[ $# -gt 0 ]]; then + EXAMPLES=("$@") +else + EXAMPLES=( + simple_email + with_attachments + with_b64_attachments + with_html_file_as_b64_attachment + with_inline_attachments + batch_email_send + ) +fi + +# --- locate repo root (this script lives in /scripts) ----------------- + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +if [[ ! -d "$REPO_ROOT/examples" || ! -d "$REPO_ROOT/resources" ]]; then + echo "Error: expected examples/ and resources/ under $REPO_ROOT" >&2 + exit 1 +fi + +PYTHON_IMAGE="${PYTHON_IMAGE:-python:3.12-slim}" + +echo "Smoke-testing resend==$VERSION in a clean $PYTHON_IMAGE container" +echo "Examples: ${EXAMPLES[*]}" +echo + +# --- run -------------------------------------------------------------------- +# +# examples/ and resources/ are mounted read-only in the same relative layout +# the examples expect (they read ../resources/). The SDK itself is NOT +# mounted — it's pulled from PyPI so we test exactly what customers get. + +docker run --rm \ + -e RESEND_API_KEY="$API_KEY" \ + -e SDK_VERSION="$VERSION" \ + -e EXAMPLES="${EXAMPLES[*]}" \ + -v "$REPO_ROOT/examples:/app/examples:ro" \ + -v "$REPO_ROOT/resources:/app/resources:ro" \ + -w /app \ + "$PYTHON_IMAGE" \ + bash -c ' + set -u + echo "==> pip install resend==$SDK_VERSION" + pip install --quiet --no-cache-dir --disable-pip-version-check "resend==$SDK_VERSION" + echo "==> installed: $(pip show resend | grep -i "^Version:")" + echo + + fail=0 + passed=() + failed=() + for ex in $EXAMPLES; do + file="examples/$ex.py" + echo "======================================================================" + echo " Running $file" + echo "======================================================================" + if [[ ! -f "$file" ]]; then + echo " SKIP (not found): $file" + failed+=("$ex (missing)") + fail=1 + continue + fi + if python "$file"; then + echo " ✅ PASS: $ex" + passed+=("$ex") + else + echo " ❌ FAIL: $ex" + failed+=("$ex") + fail=1 + fi + echo + done + + echo "======================================================================" + echo " Summary for resend==$SDK_VERSION" + echo "======================================================================" + echo " Passed: ${passed[*]:-none}" + echo " Failed: ${failed[*]:-none}" + exit $fail + ' + +status=$? +echo +if [[ $status -eq 0 ]]; then + echo "✅ Smoke test passed for resend==$VERSION" +else + echo "❌ Smoke test FAILED for resend==$VERSION (exit $status)" +fi +exit $status From bfd618a27c37dc8bdcbc6280ba805775cc8f0717 Mon Sep 17 00:00:00 2001 From: dielduarte Date: Mon, 13 Jul 2026 18:55:43 -0300 Subject: [PATCH 2/2] fix: report smoke-test failures cleanly and fail fast on pip install - Wrap docker run in an || list so a failing example doesn't trip errexit and skip the summary/status reporting block - Fail fast with a clear message when pip install of the SDK fails, instead of running every example against a missing SDK --- scripts/smoke_test_release.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/scripts/smoke_test_release.sh b/scripts/smoke_test_release.sh index f0ffeb6..cedfcf3 100755 --- a/scripts/smoke_test_release.sh +++ b/scripts/smoke_test_release.sh @@ -96,6 +96,10 @@ echo # the examples expect (they read ../resources/). The SDK itself is NOT # mounted — it's pulled from PyPI so we test exactly what customers get. +# `docker run` sits in an `|| status=$?` list so that a failing example +# (non-zero exit from the container) doesn't trip `errexit` and abort before we +# reach the summary block below. We capture the status and report it ourselves. +status=0 docker run --rm \ -e RESEND_API_KEY="$API_KEY" \ -e SDK_VERSION="$VERSION" \ @@ -107,7 +111,11 @@ docker run --rm \ bash -c ' set -u echo "==> pip install resend==$SDK_VERSION" - pip install --quiet --no-cache-dir --disable-pip-version-check "resend==$SDK_VERSION" + if ! pip install --quiet --no-cache-dir --disable-pip-version-check "resend==$SDK_VERSION"; then + echo " ❌ FAILED to install resend==$SDK_VERSION from PyPI." >&2 + echo " Check the version exists on PyPI and that the network is reachable." >&2 + exit 1 + fi echo "==> installed: $(pip show resend | grep -i "^Version:")" echo @@ -142,9 +150,8 @@ docker run --rm \ echo " Passed: ${passed[*]:-none}" echo " Failed: ${failed[*]:-none}" exit $fail - ' + ' || status=$? -status=$? echo if [[ $status -eq 0 ]]; then echo "✅ Smoke test passed for resend==$VERSION"