diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index a47af66..d374587 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -54,21 +54,42 @@ jobs: echo "minor=$MINOR" } >> "$GITHUB_OUTPUT" + # JSON API can return 200 before the simple index / CDN edges that pip + # hits inside the Docker build. Require JSON + simple-index listing + + # a reachable wheel URL before building (see #217). - name: Wait for PyPI package env: VERSION: ${{ steps.version.outputs.version }} PACKAGE: create-awesome-python-app run: | set -euo pipefail - attempts=24 + attempts=36 delay=15 + normalized="${PACKAGE//-/_}" for attempt in $(seq 1 "$attempts"); do + json_ok=0 + simple_ok=0 + wheel_ok=0 if curl -sfL "https://pypi.org/pypi/${PACKAGE}/${VERSION}/json" \ | jq -e '.urls[] | select(.packagetype=="sdist") | .digests.sha256' >/dev/null; then - echo "PyPI has ${PACKAGE}==${VERSION}" + json_ok=1 + fi + if curl -sfL "https://pypi.org/simple/${PACKAGE}/" \ + | grep -Fq "${normalized}-${VERSION}"; then + simple_ok=1 + fi + wheel_url="$(curl -sfL "https://pypi.org/pypi/${PACKAGE}/${VERSION}/json" \ + | jq -r '.urls[] | select(.packagetype=="bdist_wheel") | .url' \ + | head -n1 || true)" + if [ -n "${wheel_url}" ] && curl -sfI "$wheel_url" >/dev/null; then + wheel_ok=1 + fi + if [ "$json_ok" -eq 1 ] && [ "$simple_ok" -eq 1 ] && [ "$wheel_ok" -eq 1 ]; then + echo "PyPI ready for ${PACKAGE}==${VERSION} (json+simple+wheel)" exit 0 fi - echo "::warning::PyPI not ready for ${PACKAGE}==${VERSION} (attempt ${attempt}/${attempts}); retrying in ${delay}s" + echo "::warning::PyPI not ready for ${PACKAGE}==${VERSION}" + echo "::warning::json=${json_ok} simple=${simple_ok} wheel=${wheel_ok} attempt=${attempt}/${attempts}; sleep ${delay}s" sleep "$delay" done echo "::error::Timed out waiting for ${PACKAGE}==${VERSION} on PyPI" diff --git a/Dockerfile b/Dockerfile index f815227..5e3e111 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,13 +6,22 @@ FROM python:3.12-slim-bookworm # reproducible for its tag). ARG VERSION=latest +# Retry pip install: PyPI simple-index / CDN edges can lag the JSON API +# that CI already observed as ready (see #217). # hadolint ignore=DL3013 RUN useradd --create-home --uid 1000 --shell /bin/bash app \ && if [ "$VERSION" = "latest" ]; then \ - pip install --no-cache-dir create-awesome-python-app; \ + pkg="create-awesome-python-app"; \ else \ - pip install --no-cache-dir "create-awesome-python-app==${VERSION}"; \ - fi + pkg="create-awesome-python-app==${VERSION}"; \ + fi \ + && attempt=1 \ + && until pip install --no-cache-dir "$pkg"; do \ + if [ "$attempt" -ge 12 ]; then exit 1; fi; \ + echo "pip install failed (attempt ${attempt}/12); retrying in 15s"; \ + attempt=$((attempt + 1)); \ + sleep 15; \ + done USER app WORKDIR /home/app