name: Setup package mirrors description: Benchmark package mirrors and export the fastest reachable registry for each ecosystem inputs: npm_mirrors: description: Newline-separated npm-compatible registries required: false default: | https://npm.reg.darano.ir/ pypi_mirrors: required: false default: | https://package-mirror.liara.ir/repository/pypi/simple https://pypi.reg.darano.ir https://pypi-iran.ir/simple/ https://pypi.org/simple/ go_mirrors: description: Newline-separated Go module proxies required: false default: | https://go.devneeds.ir/ https://package-mirror.liara.ir/repository/go/ https://go.reg.darano.ir/ https://proxy.golang.org/ debian_mirrors: description: Newline-separated Debian package repository base URLs required: false default: | http://repo.iut.ac.ir/debian/ http://deb.debian.org/debian/ connect_timeout: description: curl connection timeout in seconds required: false default: "3" max_time: description: curl request timeout in seconds required: false default: "10" outputs: npm_registry: description: Fastest reachable npm registry value: ${{ steps.select.outputs.npm_registry }} pypi_index: description: Fastest reachable Python package index value: ${{ steps.select.outputs.pypi_index }} go_proxy: description: Fastest reachable Go module proxy value: ${{ steps.select.outputs.go_proxy }} debian_mirror: description: Fastest reachable Debian package repository value: ${{ steps.select.outputs.debian_mirror }} runs: using: composite steps: - name: Rate mirrors and export package environments id: select shell: bash env: NPM_MIRRORS: ${{ inputs.npm_mirrors }} PYPI_MIRRORS: ${{ inputs.pypi_mirrors }} GO_MIRRORS: ${{ inputs.go_mirrors }} DEBIAN_MIRRORS: ${{ inputs.debian_mirrors }} CONNECT_TIMEOUT: ${{ inputs.connect_timeout }} MAX_TIME: ${{ inputs.max_time }} run: | set -euo pipefail if [[ ! "$CONNECT_TIMEOUT" =~ ^[0-9]+([.][0-9]+)?$ ]] || [[ ! "$MAX_TIME" =~ ^[0-9]+([.][0-9]+)?$ ]]; then echo "Mirror timeouts must be positive numbers" >&2 exit 1 fi select_fastest() { local ecosystem="$1" local mirrors="$2" local scores mirror result status duration fallback scores="$(mktemp)" fallback="" while IFS= read -r mirror; do mirror="$(printf '%s' "$mirror" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" [[ -z "$mirror" || "$mirror" == \#* ]] && continue if [[ ! "$mirror" =~ ^https?:// ]]; then echo "[$ecosystem] skipped invalid URL: $mirror" >&2 continue fi [[ -z "$fallback" ]] && fallback="$mirror" if result="$(curl \ --location \ --silent \ --show-error \ --output /dev/null \ --connect-timeout "$CONNECT_TIMEOUT" \ --max-time "$MAX_TIME" \ --write-out '%{http_code} %{time_total}' \ "$mirror" 2>/dev/null)"; then read -r status duration <<< "$result" if [[ "$status" =~ ^[0-9]{3}$ ]] && (((10#$status >= 200 && 10#$status < 400) || 10#$status == 404)) && [[ "$duration" =~ ^[0-9]+([.][0-9]+)?$ ]]; then printf '%s\t%s\t%s\n' "$duration" "$status" "$mirror" >> "$scores" continue fi fi echo "[$ecosystem] unavailable: $mirror" >&2 done <<< "$mirrors" if [[ ! -s "$scores" ]]; then rm -f "$scores" if [[ -z "$fallback" ]]; then echo "No valid $ecosystem mirror was configured" >&2 return 1 fi echo "[$ecosystem] no mirror responded; falling back to $fallback" >&2 printf '%s\n' "$fallback" return 0 fi echo "[$ecosystem] mirror ranking (seconds, HTTP status, URL):" >&2 sort -n -k1,1 "$scores" >&2 sort -n -k1,1 "$scores" | head -n 1 | cut -f3- rm -f "$scores" } npm_registry="$(select_fastest npm "$NPM_MIRRORS")" pypi_index="$(select_fastest pypi "$PYPI_MIRRORS")" go_proxy="$(select_fastest go "$GO_MIRRORS")" debian_mirror="$(select_fastest debian "$DEBIAN_MIRRORS")" { echo "NPM_CONFIG_REGISTRY=$npm_registry" echo "npm_config_registry=$npm_registry" echo "COREPACK_NPM_REGISTRY=$npm_registry" echo "YARN_REGISTRY=$npm_registry" echo "PNPM_CONFIG_REGISTRY=$npm_registry" echo "BUN_CONFIG_REGISTRY=$npm_registry" echo "PIP_INDEX_URL=$pypi_index" echo "UV_DEFAULT_INDEX=$pypi_index" echo "GOPROXY=$go_proxy" echo "DEBIAN_MIRROR=$debian_mirror" } >> "$GITHUB_ENV" { echo "npm_registry=$npm_registry" echo "pypi_index=$pypi_index" echo "go_proxy=$go_proxy" echo "debian_mirror=$debian_mirror" } >> "$GITHUB_OUTPUT"