{"id":11925534,"name":"lfreleng-actions/python-supported-versions-action","ecosystem":"actions","description":"Returns Python version(s) for build and JSON for matrix jobs","homepage":"","licenses":"other","normalized_licenses":["GPL-1.0+"],"repository_url":"https://github.com/lfreleng-actions/python-supported-versions-action","keywords_array":["python","versions"],"namespace":"lfreleng-actions","versions_count":11,"first_release_published_at":"2025-03-16T14:23:49.000Z","latest_release_published_at":"2025-08-20T16:56:51.000Z","latest_release_number":"v0.1.10","last_synced_at":"2026-04-19T03:31:52.510Z","created_at":"2025-07-18T23:30:27.996Z","updated_at":"2026-04-19T03:31:52.510Z","registry_url":"https://github.com/lfreleng-actions/python-supported-versions-action","install_command":null,"documentation_url":null,"metadata":{"name":"🐍 Extract Python Versions Supported by Project","description":"Returns Python version(s) for build and JSON for matrix jobs","inputs":{"path_prefix":{"description":"Directory location containing project code","required":false,"default":"."},"network_timeout":{"description":"Network timeout in seconds for API calls","required":false,"default":"6"},"max_retries":{"description":"Maximum number of retry attempts for API calls","required":false,"default":"2"},"eol_behaviour":{"description":"How to handle EOL Python versions: warn|strip|fail","required":false,"default":"warn"},"offline_mode":{"description":"Disable network lookups and use internal version list only","required":false,"default":"false"}},"outputs":{"build_python":{"description":"Most recent Python version supported by project","value":"${{ steps.versions.outputs.build_python }}"},"matrix_json":{"description":"All Python versions supported by project as JSON string","value":"${{ steps.versions.outputs.matrix_json }}"},"supported_versions":{"description":"Space-separated list of all supported Python versions","value":"${{ steps.versions.outputs.supported_versions }}"}},"runs":{"using":"composite","steps":[{"id":"versions","name":"Process and determine supported Python versions","shell":"bash","env":{"INPUT_PATH_PREFIX":"${{ inputs.path_prefix }}","INPUT_NETWORK_TIMEOUT":"${{ inputs.network_timeout }}","INPUT_MAX_RETRIES":"${{ inputs.max_retries }}","INPUT_EOL_BEHAVIOUR":"${{ inputs.eol_behaviour }}","INPUT_OFFLINE_MODE":"${{ inputs.offline_mode }}"},"run":"# Process and determine supported Python versions\nset -euo pipefail\n\nTIMEOUT=\"${INPUT_NETWORK_TIMEOUT}\"\nRETRIES=\"${INPUT_MAX_RETRIES}\"\nEOL_BEHAVIOUR=\"${INPUT_EOL_BEHAVIOUR}\"\nOFFLINE_MODE=\"${INPUT_OFFLINE_MODE}\"\n\n\n# Internal list of supported Python versions (requires periodic update)\nINTERNAL_SUPPORTED_VERSIONS=\"3.9 3.10 3.11 3.12 3.13\"\n\n# Setup and validate environment\npath_prefix=\"${INPUT_PATH_PREFIX}\"\npath_prefix=\"${path_prefix:-'.'}\"\npath_prefix=\"${path_prefix%/}\"\n\n# Set PYPROJECT_FILE after path normalization\nPYPROJECT_FILE=\"${path_prefix}/pyproject.toml\"\n\n# Check tool availability\nif ! command -v jq \u003e/dev/null 2\u003e\u00261; then\n  echo 'Error: jq is required but not available. Please install jq or use a runner with jq pre-installed ❌'\n  exit 1\nfi\n\nif [[ \"$OFFLINE_MODE\" != \"true\" ]]; then\n  if ! command -v curl \u003e/dev/null 2\u003e\u00261; then\n    echo 'Error: curl is required but not available ❌'\n    exit 1\n  fi\nfi\n\n\n# Validate directory and pyproject.toml existence\nif [[ ! -d \"$path_prefix\" ]]; then\n  echo 'Error: invalid path/prefix to project directory ❌'\n  exit 1\nfi\n\nif [[ ! -f \"$path_prefix/pyproject.toml\" ]]; then\n  echo 'Error: missing pyproject.toml file ❌'\n  exit 1\nfi\n\n# Validate eol_behaviour input\nif [[ \"$EOL_BEHAVIOUR\" != \"warn\" \u0026\u0026 \"$EOL_BEHAVIOUR\" != \"strip\" \u0026\u0026 \\\n      \"$EOL_BEHAVIOUR\" != \"fail\" ]]; then\n  echo 'Error: eol_behaviour must be one of: warn, strip, fail ❌'\n  exit 1\nfi\n\n# Validate offline_mode input\nif [[ \"$OFFLINE_MODE\" != \"true\" \u0026\u0026 \"$OFFLINE_MODE\" != \"false\" ]]; then\n  echo 'Error: offline_mode must be true or false ❌'\n  exit 1\nfi\n\n# Validate numeric inputs for network timeout and max retries\nif ! [[ \"$TIMEOUT\" =~ ^[0-9]+$ ]]; then\n  echo 'Error: network_timeout must be a non-negative integer ❌'\n  exit 1\nfi\nif ! [[ \"$RETRIES\" =~ ^[0-9]+$ ]]; then\n  echo 'Error: max_retries must be a non-negative integer ❌'\n  exit 1\nfi\n\n# Function: Portable version comparison (major.minor format)\nversion_compare() {\n    local v1=\"$1\"\n    local op=\"$2\"\n    local v2=\"$3\"\n\n    # Split versions into major.minor\n    local v1_major=\"${v1%%.*}\"\n    local v1_minor=\"${v1##*.}\"\n    local v2_major=\"${v2%%.*}\"\n    local v2_minor=\"${v2##*.}\"\n\n    # Convert to integers for comparison\n    v1_major=$((v1_major))\n    v1_minor=$((v1_minor))\n    v2_major=$((v2_major))\n    v2_minor=$((v2_minor))\n\n    case \"$op\" in\n        \"lt\")\n            [[ $v1_major -lt $v2_major ]] || \\\n            [[ $v1_major -eq $v2_major \u0026\u0026 $v1_minor -lt $v2_minor ]]\n            ;;\n        \"le\")\n            [[ $v1_major -lt $v2_major ]] || \\\n            [[ $v1_major -eq $v2_major \u0026\u0026 $v1_minor -le $v2_minor ]]\n            ;;\n        \"gt\")\n            [[ $v1_major -gt $v2_major ]] || \\\n            [[ $v1_major -eq $v2_major \u0026\u0026 $v1_minor -gt $v2_minor ]]\n            ;;\n        \"ge\")\n            [[ $v1_major -gt $v2_major ]] || \\\n            [[ $v1_major -eq $v2_major \u0026\u0026 $v1_minor -ge $v2_minor ]]\n            ;;\n        \"eq\")\n            [[ $v1_major -eq $v2_major \u0026\u0026 $v1_minor -eq $v2_minor ]]\n            ;;\n        *)\n            echo \"Invalid comparison operator: $op\" \u003e\u00262\n            return 1\n            ;;\n    esac\n}\n\n# Function: Portable version sorting\nsort_versions() {\n    local versions=\"$1\"\n    # Use numeric sort on major and minor parts, then join back to space-separated string\n    printf '%s\\n' \"$versions\" | tr ' ' '\\n' | sort -t. -k1,1n -k2,2n | tr '\\n' ' ' | sed 's/ $//'\n}\n\n# Function: Fetch Python EOL data and optionally format as version list\nfetch_python_data() {\n    local timeout=\"$1\"\n    local retries=\"$2\"\n    local format=\"${3:-raw}\"  # Default to raw format\n    local eol_data\n\n    if [[ \"$OFFLINE_MODE\" == \"true\" ]]; then\n        if [[ \"$format\" == \"versions\" ]]; then\n            printf '%s\\n' \"$INTERNAL_SUPPORTED_VERSIONS\"\n        else\n            echo \"[]\"  # Empty array for offline mode\n        fi\n        return 0\n    fi\n\n    # Fetch data with error checking\n    # Determine if curl supports --retry-all-errors; fallback if not\n    local curl_retry_flag=\"\"\n    if curl --help 2\u003e/dev/null | grep -q -- '--retry-all-errors'; then\n        curl_retry_flag=\"--retry-all-errors\"\n    fi\n    if eol_data=$(curl -s --max-time \"$timeout\" --retry \"$retries\" $curl_retry_flag 'https://endoflife.date/api/python.json' 2\u003e/dev/null); then\n        # Verify we got valid JSON array with expected structure\n        if [[ -n \"$eol_data\" ]] \u0026\u0026 echo \"$eol_data\" | jq -e 'type==\"array\" and length\u003e0 and all(.[]; has(\"cycle\"))' \u003e/dev/null 2\u003e\u00261; then\n            if [[ \"$format\" == \"versions\" ]]; then\n                # Return processed version list (3.9+)\n                printf '%s\\n' \"$eol_data\" | \\\n                  jq -r '.[] | select(.cycle | test(\"^(3\\\\.(9|[1-9][0-9])|[4-9][0-9]*\\\\.[0-9]+)$\")) | .cycle' | \\\n                  tr '\\n' ' ' | sed 's/ $//'\n            else\n                # Return raw JSON data\n                echo \"$eol_data\"\n            fi\n            return 0\n        else\n            echo \"Error: Invalid or empty EOL data received\" \u003e\u00262\n            return 1\n        fi\n    else\n        echo \"Error: Failed to fetch EOL data from API\" \u003e\u00262\n        return 1\n    fi\n}\n\n# Function: Check if a version is EOL\ncheck_version_eol() {\n    local version=\"$1\"\n    local eol_data=\"$2\"\n    local current_date eol_date eol_type\n\n    if [[ \"$OFFLINE_MODE\" == \"true\" ]]; then\n        echo \"false\"\n        return 0\n    fi\n\n    current_date=$(date +%Y-%m-%d)\n\n    # Extract EOL date for the specific version, handling different types\n    local eol_info\n    eol_info=$(printf '%s\\n' \"$eol_data\" | \\\n      jq -r --arg ver \"$version\" \\\n      '.[] | select(.cycle == $ver) | {eol: .eol, type: (.eol | type)}' 2\u003e/dev/null)\n\n    if [[ -z \"$eol_info\" || \"$eol_info\" == \"null\" ]]; then\n        echo \"false\"\n        return 0\n    fi\n\n    eol_date=$(echo \"$eol_info\" | jq -r '.eol // \"null\"')\n    eol_type=$(echo \"$eol_info\" | jq -r '.type')\n\n    # Handle different EOL field types\n    case \"$eol_type\" in\n        \"string\")\n            if [[ \"$eol_date\" != \"null\" \u0026\u0026 \"$eol_date\" != \"\" ]]; then\n                if [[ \"$eol_date\" \u003c \"$current_date\" || \"$eol_date\" == \"$current_date\" ]]; then\n                    echo \"$eol_date\"\n                else\n                    echo \"false\"\n                fi\n            else\n                echo \"false\"\n            fi\n            ;;\n        \"boolean\")\n            # If EOL is boolean true, it's EOL (no specific date)\n            if [[ \"$eol_date\" == \"true\" ]]; then\n                echo \"true\"\n            else\n                echo \"false\"\n            fi\n            ;;\n        *)\n            echo \"false\"\n            ;;\n    esac\n}\n\n# Function: Normalize constraint (handle ~= and ^ operators)\nnormalize_constraint() {\n    local constraint=\"$1\"\n\n    # Leave exclusions untouched so the parser can handle them precisely\n    if [[ \"$constraint\" == \\!* ]]; then\n        echo \"$constraint\"\n        return 0\n    fi\n\n    # Handle Poetry caret constraints with patch: ^3.10.1 -\u003e \u003e=3.10,\u003c4.0\n    if [[ \"$constraint\" =~ ^\\^([0-9]+)\\.([0-9]+)\\.([0-9]+)$ ]]; then\n        local major=\"${BASH_REMATCH[1]}\"\n        local minor=\"${BASH_REMATCH[2]}\"\n        local next_major=$((major + 1))\n        echo \"\u003e=${major}.${minor},\u003c${next_major}.0\"\n        return 0\n    fi\n\n    # Handle Poetry caret constraints: ^3.10 -\u003e \u003e=3.10,\u003c4.0\n    if [[ \"$constraint\" =~ ^\\^([0-9]+)\\.([0-9]+)$ ]]; then\n        local major=\"${BASH_REMATCH[1]}\"\n        local minor=\"${BASH_REMATCH[2]}\"\n        local next_major=$((major + 1))\n        echo \"\u003e=${major}.${minor},\u003c${next_major}.0\"\n        return 0\n    fi\n\n    # Handle compatible release with patch: ~=3.10.1 -\u003e \u003e=3.10,\u003c3.11\n    if [[ \"$constraint\" =~ ^~=([0-9]+)\\.([0-9]+)\\.([0-9]+)$ ]]; then\n        local major=\"${BASH_REMATCH[1]}\"\n        local minor=\"${BASH_REMATCH[2]}\"\n        local next_minor=$((minor + 1))\n        echo \"\u003e=${major}.${minor},\u003c${major}.${next_minor}\"\n        return 0\n    fi\n\n    # Handle compatible release: ~=3.10 -\u003e \u003e=3.10,\u003c3.11\n    if [[ \"$constraint\" =~ ^~=([0-9]+)\\.([0-9]+)$ ]]; then\n        local major=\"${BASH_REMATCH[1]}\"\n        local minor=\"${BASH_REMATCH[2]}\"\n        local next_minor=$((minor + 1))\n        echo \"\u003e=${major}.${minor},\u003c${major}.${next_minor}\"\n        return 0\n    fi\n\n    # Handle wildcard constraints: ==3.10.* -\u003e \u003e=3.10,\u003c3.11\n    if [[ \"$constraint\" =~ ^==([0-9]+)\\.([0-9]+)\\.\\*$ ]]; then\n        local major=\"${BASH_REMATCH[1]}\"\n        local minor=\"${BASH_REMATCH[2]}\"\n        local next_minor=$((minor + 1))\n        echo \"\u003e=${major}.${minor},\u003c${major}.${next_minor}\"\n        return 0\n    fi\n\n    # Strip patch versions from bounds: \u003c3.13.0 -\u003e \u003c3.13 (does not affect '!=')\n    constraint=$(echo \"$constraint\" | sed 's/\\([\u003c\u003e=]\\+\\)\\([0-9]\\+\\.[0-9]\\+\\)\\.[0-9]\\+/\\1\\2/g')\n\n    # Return normalized constraint\n    echo \"$constraint\"\n}\n\n# Function: Extract requires-python constraint from pyproject.toml using Python\nextract_requires_python_python() {\n    local pyproject_file=\"$1\"\n\n    if [[ ! -f \"$pyproject_file\" ]]; then\n        return 1\n    fi\n\n    # Try using Python with tomllib (Python 3.11+) or tomli\n    python3 -c \"import sys, importlib.util as iu; fp=sys.argv[1]; tmod='tomllib' if iu.find_spec('tomllib') else ('tomli' if iu.find_spec('tomli') else 'toml'); t=__import__(tmod); data=t.load(open(fp, 'rb' if tmod!='toml' else 'r')); v=(data.get('project', {}).get('requires-python') or data.get('tool', {}).get('poetry', {}).get('dependencies', {}).get('python')); print(v) if v else None; sys.exit(0 if v else 1)\" \"$pyproject_file\" 2\u003e/dev/null\n}\n\n# Function: Extract requires-python constraint from pyproject.toml (fallback)\nextract_requires_python_fallback() {\n    local pyproject_file=\"$1\"\n    local constraint\n\n    if [[ ! -f \"$pyproject_file\" ]]; then\n        return 1\n    fi\n\n    # Extract requires-python constraint, supporting both single and double quotes\n    # Ignore commented lines\n    constraint=$(grep -v '^[[:space:]]*#' \"$pyproject_file\" 2\u003e/dev/null | \\\n                 grep 'requires-python.*=' | \\\n                 sed -E 's/.*requires-python.*=[[:space:]]*['\\''\"]([^'\\''\"]*)['\\''\"].*/\\1/' | \\\n                 head -1)\n\n    if [[ -n \"$constraint\" ]]; then\n        printf '%s\\n' \"$constraint\"\n        return 0\n    fi\n\n    # Fall back to Poetry python dependency (robust section parsing)\n    constraint=$(awk '\n      BEGIN{insec=0}\n      /^\\[tool\\.poetry\\.dependencies\\]/{insec=1; next}\n      /^\\[.*\\]/{if(insec) exit}\n      insec{print}\n    ' \"$pyproject_file\" 2\u003e/dev/null | grep -v '^[[:space:]]*#' | grep -E '^[[:space:]]*python[[:space:]]*=' | sed -E 's/.*=[[:space:]]*['\\''\"]([^'\\''\"]*)['\\''\"].*/\\1/' | head -1)\n\n    if [[ -n \"$constraint\" ]]; then\n        printf '%s\\n' \"$constraint\"\n        return 0\n    else\n        return 1\n    fi\n}\n\n# Function: Extract Programming Language classifiers from pyproject.toml\nextract_classifiers_fallback() {\n    local pyproject_file=\"$1\"\n    local classifiers\n\n    if [[ ! -f \"$pyproject_file\" ]]; then\n        return 1\n    fi\n\n    # Extract Python versions from Programming Language classifiers\n    # Support both single and double quotes, ignore commented lines\n    classifiers=$(grep -v '^[[:space:]]*#' \"$pyproject_file\" 2\u003e/dev/null | \\\n                  grep -E 'Programming Language :: Python :: [0-9]+\\.[0-9]+' | \\\n                  grep -oE '[0-9]+\\.[0-9]+' | \\\n                  sort -u | tr '\\n' ' ' | sed 's/ *$//')\n\n    if [[ -n \"$classifiers\" ]]; then\n        printf '%s\\n' \"$classifiers\"\n        return 0\n    else\n        return 1\n    fi\n}\n\n# Function: Parse version constraint and return all matching versions\nparse_version_constraint() {\n    local constraint=\"$1\"\n    local all_versions=\"$2\"\n    local result=''\n\n    # Normalize the constraint first\n    constraint=$(normalize_constraint \"$constraint\")\n\n    # Handle complex constraints with multiple parts (e.g., \"\u003e=3.11,\u003c3.13\")\n    if [[ \"$constraint\" == *\",\"* ]]; then\n        local candidates=\"$all_versions\"\n\n        # Split by comma and process each constraint part\n        local IFS=','\n        local -a parts\n        read -ra parts \u003c\u003c\u003c \"$constraint\"\n        unset IFS\n\n        for part in \"${parts[@]}\"; do\n            # Trim whitespace\n            part=$(echo \"$part\" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')\n            local temp_result=''\n\n            case \"$part\" in\n                \\\u003e=*)\n                    local min_version=\"${part#\u003e=}\"\n                    for version in $candidates; do\n                        if version_compare \"$version\" \"ge\" \"$min_version\"; then\n                            temp_result=\"$temp_result $version\"\n                        fi\n                    done\n                    ;;\n                \\\u003e*)\n                    local min_version=\"${part#\u003e}\"\n                    for version in $candidates; do\n                        if version_compare \"$version\" \"gt\" \"$min_version\"; then\n                            temp_result=\"$temp_result $version\"\n                        fi\n                    done\n                    ;;\n                \\\u003c=*)\n                    local max_version=\"${part#\u003c=}\"\n                    for version in $candidates; do\n                        if version_compare \"$version\" \"le\" \"$max_version\"; then\n                            temp_result=\"$temp_result $version\"\n                        fi\n                    done\n                    ;;\n                \\\u003c*)\n                    local max_version=\"${part#\u003c}\"\n                    for version in $candidates; do\n                        if version_compare \"$version\" \"lt\" \"$max_version\"; then\n                            temp_result=\"$temp_result $version\"\n                        fi\n                    done\n                    ;;\n                ==*)\n                    local exact_version=\"${part#==}\"\n                    for version in $candidates; do\n                        if version_compare \"$version\" \"eq\" \"$exact_version\"; then\n                            temp_result=\"$version\"\n                            break\n                        fi\n                    done\n                    ;;\n                \\!\\=*)\n                    local exclude_raw=\"${part#!=}\"\n                    local exclude_target=\"\"\n                    if [[ \"$exclude_raw\" =~ ^([0-9]+)\\.([0-9]+) ]]; then\n                        exclude_target=\"${BASH_REMATCH[1]}.${BASH_REMATCH[2]}\"\n                    else\n                        exclude_target=\"$exclude_raw\"\n                    fi\n                    for version in $candidates; do\n                        if ! version_compare \"$version\" \"eq\" \"$exclude_target\"; then\n                            temp_result=\"$temp_result $version\"\n                        fi\n                    done\n                    ;;\n                *)\n                    echo \"Warning: Unsupported constraint part: $part\" \u003e\u00262\n                    return 1\n                    ;;\n            esac\n\n            # Update candidates to be the filtered result\n            if [[ -n \"$temp_result\" ]]; then\n                candidates=$(echo \"$temp_result\" | tr ' ' '\\n' | grep -v '^$' | \\\n                           sort -u | tr '\\n' ' ' | sed 's/ *$//')\n            else\n                candidates=''\n                break  # No matches found, no point continuing\n            fi\n        done\n\n        result=\"$candidates\"\n    else\n        # Handle simple constraints\n        case \"$constraint\" in\n            \\\u003e=*)\n                local min_version=\"${constraint#\u003e=}\"\n                for version in $all_versions; do\n                    if version_compare \"$version\" \"ge\" \"$min_version\"; then\n                        result=\"$result $version\"\n                    fi\n                done\n                ;;\n            \\\u003e*)\n                local min_version=\"${constraint#\u003e}\"\n                for version in $all_versions; do\n                    if version_compare \"$version\" \"gt\" \"$min_version\"; then\n                        result=\"$result $version\"\n                    fi\n                done\n                ;;\n            \\\u003c=*)\n                local max_version=\"${constraint#\u003c=}\"\n                for version in $all_versions; do\n                    if version_compare \"$version\" \"le\" \"$max_version\"; then\n                        result=\"$result $version\"\n                    fi\n                done\n                ;;\n            \\\u003c*)\n                local max_version=\"${constraint#\u003c}\"\n                for version in $all_versions; do\n                    if version_compare \"$version\" \"lt\" \"$max_version\"; then\n                        result=\"$result $version\"\n                    fi\n                done\n                ;;\n            ==*)\n                local exact_version=\"${constraint#==}\"\n                for version in $all_versions; do\n                    if version_compare \"$version\" \"eq\" \"$exact_version\"; then\n                        result=\"$version\"\n                        break\n                    fi\n                done\n                ;;\n            \\!\\=*)\n                local exclude_raw=\"${constraint#!=}\"\n                local exclude_target=\"\"\n                if [[ \"$exclude_raw\" =~ ^([0-9]+)\\.([0-9]+) ]]; then\n                    exclude_target=\"${BASH_REMATCH[1]}.${BASH_REMATCH[2]}\"\n                else\n                    exclude_target=\"$exclude_raw\"\n                fi\n                for version in $all_versions; do\n                    if ! version_compare \"$version\" \"eq\" \"$exclude_target\"; then\n                        result=\"$result $version\"\n                    fi\n                done\n                ;;\n            *)\n                echo \"Warning: Unsupported constraint format: $constraint\" \u003e\u00262\n                return 1\n                ;;\n        esac\n    fi\n\n    # Clean up, sort, and return result\n    result=$(printf '%s\\n' \"$result\" | sed 's/^ *//' | sed 's/ *$//')\n    if [[ -n \"$result\" ]]; then\n        # Ensure final result is properly sorted\n        result=$(sort_versions \"$result\")\n        printf '%s\\n' \"$result\"\n        return 0\n    else\n        return 1\n    fi\n}\n\n# Function: Handle EOL versions based on behaviour setting\nhandle_eol_versions() {\n    local requested_versions=\"$1\"\n    local eol_behaviour=\"$2\"\n    local timeout=\"$3\"\n    local retries=\"$4\"\n    local final_versions=\"\"\n    local eol_data\n\n    if [[ \"$OFFLINE_MODE\" == \"true\" ]]; then\n        [ -n \"${GITHUB_STEP_SUMMARY:-}\" ] \u0026\u0026 echo \"⚠️ Warning: Offline mode enabled, EOL filtering disabled\" \u003e\u003e \"$GITHUB_STEP_SUMMARY\"\n        printf '%s\\n' \"$requested_versions\"\n        return 0\n    fi\n\n    # Fetch EOL data once\n    if ! eol_data=$(fetch_python_data \"$timeout\" \"$retries\" \"raw\"); then\n      echo \"⚠️ Warning: Could not fetch EOL data, proceeding with all requested versions\" \u003e\u00262\n      [ -n \"${GITHUB_STEP_SUMMARY:-}\" ] \u0026\u0026 echo \"⚠️ Warning: EOL filtering disabled due to API failure\" \u003e\u003e \"$GITHUB_STEP_SUMMARY\"\n      printf '%s\\n' \"$requested_versions\"\n      return 0\n    fi\n\n    echo \"✅ Successfully fetched EOL data for version filtering\" \u003e\u00262\n\n    # Process each version individually\n    for version in $requested_versions; do\n        local eol_result\n        eol_result=$(check_version_eol \"$version\" \"$eol_data\")\n\n        if [[ \"$eol_result\" != \"false\" ]]; then\n            # This version is EOL\n            case \"$eol_behaviour\" in\n                \"warn\")\n                    local message\n                    if [[ \"$eol_result\" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then\n                      message=\"⚠️ Warning: Python $version is EOL (end-of-life date: $eol_result)\"\n                    else\n                      message=\"⚠️ Warning: Python $version is EOL\"\n                    fi\n                    echo \"$message\" \u003e\u00262\n                    [ -n \"${GITHUB_STEP_SUMMARY:-}\" ] \u0026\u0026 echo \"$message\" \u003e\u003e \"$GITHUB_STEP_SUMMARY\"\n                    # Include this version in final list\n                    final_versions=\"$final_versions $version\"\n                    ;;\n                \"strip\")\n                    local message\n                    if [[ \"$eol_result\" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then\n                      message=\"⚠️ Warning: Python $version is EOL (end-of-life date: $eol_result) - removing from matrix\"\n                    else\n                      message=\"⚠️ Warning: Python $version is EOL - removing from matrix\"\n                    fi\n                    echo \"$message\" \u003e\u00262\n                    [ -n \"${GITHUB_STEP_SUMMARY:-}\" ] \u0026\u0026 echo \"$message\" \u003e\u003e \"$GITHUB_STEP_SUMMARY\"\n                    # Do not include this version in final list\n                    ;;\n                \"fail\")\n                    local message\n                    if [[ \"$eol_result\" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then\n                      message=\"🛑 Error: Python $version is EOL (end-of-life date: $eol_result)\"\n                    else\n                      message=\"🛑 Error: Python $version is EOL\"\n                    fi\n                    echo \"$message\" \u003e\u00262\n                    [ -n \"${GITHUB_STEP_SUMMARY:-}\" ] \u0026\u0026 echo \"$message\" \u003e\u003e \"$GITHUB_STEP_SUMMARY\"\n                    exit 1\n                    ;;\n            esac\n        else\n            # This version is not EOL, include it\n            final_versions=\"$final_versions $version\"\n        fi\n    done\n\n    # Clean up whitespace and return\n    final_versions=$(echo \"$final_versions\" | sed 's/^ *//' | sed 's/ *$//')\n    printf '%s\\n' \"$final_versions\"\n}\n\n# Function: Generate matrix JSON from space-separated version list\ngenerate_matrix_json() {\n    local versions=\"$1\"\n\n    if [[ -z \"$versions\" ]]; then\n        echo '{\"python-version\": []}'\n        return 0\n    fi\n\n    # Use jq to properly construct JSON array\n    echo \"$versions\" | tr ' ' '\\n' | jq -R . | jq -s -c '{\"python-version\": .}'\n}\n\n# Function: Get the latest/build version from a list of versions\nget_build_version() {\n    local versions=\"$1\"\n\n    if [[ -z \"$versions\" ]]; then\n        return 1\n    fi\n\n    # Sort and get the last (highest) version\n    local sorted_versions\n    sorted_versions=$(sort_versions \"$versions\")\n    echo \"$sorted_versions\" | tr ' ' '\\n' | tail -1\n}\n\n# Function: Validate that all versions have correct format\nvalidate_version_format() {\n    local versions=\"$1\"\n\n    for version in $versions; do\n        if [[ ! \"$version\" =~ ^[0-9]+\\.[0-9]+$ ]]; then\n            echo \"Invalid version format: '$version'\" \u003e\u00262\n            return 1\n        fi\n    done\n\n    return 0\n}\n\n# Function: Validate JSON format using jq\nvalidate_json_format() {\n    local json=\"$1\"\n\n    if echo \"$json\" | jq -e . \u003e/dev/null 2\u003e\u00261; then\n        return 0\n    else\n        return 1\n    fi\n}\n\n### Main execution starts here ###\n\n# Get supported Python versions\nif SUPPORTED_VERSIONS=$(fetch_python_data \"$TIMEOUT\" \"$RETRIES\" \"versions\"); then\n  if [[ \"$OFFLINE_MODE\" == \"true\" ]]; then\n      echo \"Using internal supported Python versions (offline mode) 📴\"\n  else\n      echo \"Retrieved supported Python versions from API service 🌍\"\n  fi\nelse\n  echo \"Unable to retrieve supported Python versions, using internal list ⚠️\"\n  SUPPORTED_VERSIONS=\"$INTERNAL_SUPPORTED_VERSIONS\"\nfi\necho \"Supported versions: $SUPPORTED_VERSIONS\"\n\n# Extract requires-python constraint\nREQUIRES_PYTHON=\"\"\nif command -v python3 \u003e/dev/null 2\u003e\u00261; then\n    if REQUIRES_PYTHON=$(extract_requires_python_python \"$PYPROJECT_FILE\"); then\n      echo \"Found requires-python constraint (via Python): $REQUIRES_PYTHON\"\n    fi\nfi\n\n# Fall back to grep/sed parsing if Python parsing failed\nif [[ -z \"$REQUIRES_PYTHON\" ]]; then\n    if REQUIRES_PYTHON=$(extract_requires_python_fallback \"$PYPROJECT_FILE\"); then\n      echo \"Found requires-python constraint (via fallback): $REQUIRES_PYTHON\"\n    fi\nfi\n\n# Extract classifiers fallback\nCLASSIFIERS=\"\"\nif CLASSIFIERS=$(extract_classifiers_fallback \"$PYPROJECT_FILE\"); then\n  echo \"Programming Language classifiers: $CLASSIFIERS\"\nfi\n\n# Check if any constraints were found\nif [[ -z \"$REQUIRES_PYTHON\" \u0026\u0026 -z \"$CLASSIFIERS\" ]]; then\n  echo \"Error: No Python version constraints found in $PYPROJECT_FILE ❌\"\n  exit 1\nfi\n\n# Process constraints and determine requested versions\nREQUESTED_PYTHON_VERSIONS=\"\"\n\n# Try requires-python first\nif [[ -n \"$REQUIRES_PYTHON\" ]]; then\n    if REQUESTED_PYTHON_VERSIONS=$(parse_version_constraint \"$REQUIRES_PYTHON\" \"$SUPPORTED_VERSIONS\"); then\n        echo \"🔍 Processed requires-python constraint successfully\"\n        # Clean up whitespace\n        REQUESTED_PYTHON_VERSIONS=$(echo \"$REQUESTED_PYTHON_VERSIONS\" | sed 's/^ *//' | sed 's/ *$//')\n    fi\nfi\n\n# Fall back to classifiers if no versions from requires-python\nif [[ -z \"$REQUESTED_PYTHON_VERSIONS\" \u0026\u0026 -n \"$CLASSIFIERS\" ]]; then\n    REQUESTED_PYTHON_VERSIONS=\"$CLASSIFIERS\"\n    echo \"Using Programming Language classifiers fallback ⏪\"\nfi\n\n# Validate results\nif [[ -z \"$REQUESTED_PYTHON_VERSIONS\" ]]; then\n    echo \"Error: Failed to determine Python versions from constraints ❌\"\n    exit 1\nfi\n\nif ! validate_version_format \"$REQUESTED_PYTHON_VERSIONS\"; then\n    echo \"Error: Invalid version format detected ❌\"\n    echo \"Versions: $REQUESTED_PYTHON_VERSIONS\"\n    exit 1\nfi\n\necho \"Python versions from constraints: $REQUESTED_PYTHON_VERSIONS\"\n\n# Handle EOL versions based on eol_behaviour setting\nFINAL_PYTHON_VERSIONS=$(handle_eol_versions \"$REQUESTED_PYTHON_VERSIONS\" \"$EOL_BEHAVIOUR\" \"$TIMEOUT\" \"$RETRIES\")\n\n# Validate final results\nif [[ -z \"$FINAL_PYTHON_VERSIONS\" ]]; then\n    echo \"Error: No supported Python versions after EOL processing ❌\"\n    exit 1\nfi\n\n# Sort and clean final versions\nFINAL_PYTHON_VERSIONS=$(sort_versions \"$FINAL_PYTHON_VERSIONS\")\n\n# Generate build version and matrix JSON\nif BUILD_PYTHON=$(get_build_version \"$FINAL_PYTHON_VERSIONS\"); then\n  echo \"Build Python: $BUILD_PYTHON\"\nelse\n  echo \"Error: Failed to determine build Python version ❌\"\n  exit 1\nfi\n\nif MATRIX_JSON=$(generate_matrix_json \"$FINAL_PYTHON_VERSIONS\") \u0026\u0026 \\\n  validate_json_format \"$MATRIX_JSON\"; then\n  echo \"Matrix JSON generated successfully\"\nelse\n  echo \"Error: Failed to generate matrix JSON ❌\"\n  exit 1\nfi\n\n# Set outputs\necho \"build_python=$BUILD_PYTHON\" \u003e\u003e \"$GITHUB_OUTPUT\"\n{\n  echo \"matrix_json\u003c\u003c__PY_MATRIX_JSON__\"\n  echo \"$MATRIX_JSON\"\n  echo \"__PY_MATRIX_JSON__\"\n} \u003e\u003e \"$GITHUB_OUTPUT\"\necho \"supported_versions=$FINAL_PYTHON_VERSIONS\" \u003e\u003e \"$GITHUB_OUTPUT\"\n\n# Final clean output\necho \"✅ Build Python: $BUILD_PYTHON\"\necho \"✅ Supported versions: $FINAL_PYTHON_VERSIONS\"\necho \"✅ Matrix JSON: $MATRIX_JSON\"\n"}]},"default_branch":"main","path":null},"repo_metadata":{"id":282433301,"uuid":"947919055","full_name":"lfreleng-actions/python-supported-versions-action","owner":"lfreleng-actions","description":"Extracts supported Python versions from the project metadata file","archived":false,"fork":false,"pushed_at":"2025-12-22T18:18:47.000Z","size":221,"stargazers_count":0,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-24T07:39:47.408Z","etag":null,"topics":["python","versions"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lfreleng-actions.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-03-13T13:05:56.000Z","updated_at":"2025-12-16T23:10:53.000Z","dependencies_parsed_at":null,"dependency_job_id":"62979212-d29e-4503-a59b-ad11e62bfac5","html_url":"https://github.com/lfreleng-actions/python-supported-versions-action","commit_stats":null,"previous_names":["lfreleng-actions/python-supported-versions-action"],"tags_count":11,"template":false,"template_full_name":"lfreleng-actions/actions-template","purl":"pkg:github/lfreleng-actions/python-supported-versions-action","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lfreleng-actions","download_url":"https://codeload.github.com/lfreleng-actions/python-supported-versions-action/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28035463,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-25T02:00:05.988Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"},"owner_record":{"login":"lfreleng-actions","name":"LF Release Engineering Actions","uuid":"202967442","kind":"organization","description":"GitHub Actions used by LF Release Engineering","email":"releng+gha@linuxfoundation.org","website":"https://docs.releng.linuxfoundation.org/","location":null,"twitter":null,"company":null,"icon_url":"https://avatars.githubusercontent.com/u/202967442?v=4","repositories_count":1,"last_synced_at":"2025-03-12T16:39:35.120Z","metadata":{"has_sponsors_listing":false},"html_url":"https://github.com/lfreleng-actions","funding_links":[],"total_stars":0,"followers":0,"following":0,"created_at":"2025-03-12T16:39:35.144Z","updated_at":"2025-03-12T16:39:35.144Z","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lfreleng-actions","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lfreleng-actions/repositories"},"tags":[{"name":"v0.1.10","sha":"206ef1eec65ca46c8cace56db14f1172e172eafe","kind":"tag","published_at":"2025-08-20T16:56:51.000Z","download_url":"https://codeload.github.com/lfreleng-actions/python-supported-versions-action/tar.gz/v0.1.10","html_url":"https://github.com/lfreleng-actions/python-supported-versions-action/releases/tag/v0.1.10","dependencies_parsed_at":"2025-08-28T07:52:47.720Z","dependency_job_id":null,"purl":"pkg:github/lfreleng-actions/python-supported-versions-action@v0.1.10","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.10","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.10/manifests"},{"name":"v0.1.9","sha":"c580b8937b1f2485970207d899a316f155da049e","kind":"tag","published_at":"2025-08-20T13:48:51.000Z","download_url":"https://codeload.github.com/lfreleng-actions/python-supported-versions-action/tar.gz/v0.1.9","html_url":"https://github.com/lfreleng-actions/python-supported-versions-action/releases/tag/v0.1.9","dependencies_parsed_at":"2025-08-28T07:52:47.975Z","dependency_job_id":null,"purl":"pkg:github/lfreleng-actions/python-supported-versions-action@v0.1.9","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.9","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.9/manifests"},{"name":"v0.1.8","sha":"de90658c86815a5fd377497e4d45c93ece3eb499","kind":"tag","published_at":"2025-08-07T22:56:26.000Z","download_url":"https://codeload.github.com/lfreleng-actions/python-supported-versions-action/tar.gz/v0.1.8","html_url":"https://github.com/lfreleng-actions/python-supported-versions-action/releases/tag/v0.1.8","dependencies_parsed_at":null,"dependency_job_id":"f202b725-8bdb-45ed-b853-2b655ce74b92","purl":"pkg:github/lfreleng-actions/python-supported-versions-action@v0.1.8","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.8","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.8/manifests"},{"name":"v0.1.7","sha":"10baeaabac508008f3c4f29b35c49bceb9b1662e","kind":"tag","published_at":"2025-07-15T17:35:17.000Z","download_url":"https://codeload.github.com/lfreleng-actions/python-supported-versions-action/tar.gz/v0.1.7","html_url":"https://github.com/lfreleng-actions/python-supported-versions-action/releases/tag/v0.1.7","dependencies_parsed_at":"2025-07-21T05:11:37.035Z","dependency_job_id":null,"purl":"pkg:github/lfreleng-actions/python-supported-versions-action@v0.1.7","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.7","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.7/manifests"},{"name":"v0.1.6","sha":"14c5f9025a652062849adb771ff75da771886732","kind":"tag","published_at":"2025-07-10T18:19:01.000Z","download_url":"https://codeload.github.com/lfreleng-actions/python-supported-versions-action/tar.gz/v0.1.6","html_url":"https://github.com/lfreleng-actions/python-supported-versions-action/releases/tag/v0.1.6","dependencies_parsed_at":"2025-07-21T05:11:39.461Z","dependency_job_id":null,"purl":"pkg:github/lfreleng-actions/python-supported-versions-action@v0.1.6","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.6","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.6/manifests"},{"name":"v0.1.5","sha":"011ec4085152a59eb60acf06e1da0e023feebaad","kind":"tag","published_at":"2025-04-09T01:43:56.000Z","download_url":"https://codeload.github.com/lfreleng-actions/python-supported-versions-action/tar.gz/v0.1.5","html_url":"https://github.com/lfreleng-actions/python-supported-versions-action/releases/tag/v0.1.5","dependencies_parsed_at":"2025-07-21T05:11:53.677Z","dependency_job_id":null,"purl":"pkg:github/lfreleng-actions/python-supported-versions-action@v0.1.5","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.5","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.5/manifests"},{"name":"v0.1.4","sha":"e5f39afc35307199a3c03176f6c7d3f9e6d4b1ea","kind":"tag","published_at":"2025-04-09T01:23:53.000Z","download_url":"https://codeload.github.com/lfreleng-actions/python-supported-versions-action/tar.gz/v0.1.4","html_url":"https://github.com/lfreleng-actions/python-supported-versions-action/releases/tag/v0.1.4","dependencies_parsed_at":"2025-07-21T05:11:47.333Z","dependency_job_id":null,"purl":"pkg:github/lfreleng-actions/python-supported-versions-action@v0.1.4","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.4","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.4/manifests"},{"name":"v0.1.3","sha":"7040daaa69e77cb3fe4dda9d40d88a14b71bc501","kind":"tag","published_at":"2025-04-05T02:58:28.000Z","download_url":"https://codeload.github.com/lfreleng-actions/python-supported-versions-action/tar.gz/v0.1.3","html_url":"https://github.com/lfreleng-actions/python-supported-versions-action/releases/tag/v0.1.3","dependencies_parsed_at":"2025-07-21T05:11:42.805Z","dependency_job_id":null,"purl":"pkg:github/lfreleng-actions/python-supported-versions-action@v0.1.3","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.3","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.3/manifests"},{"name":"v0.1.2","sha":"53523fcecb0fb32f2e09d2b6c587b6d876cfeb1d","kind":"tag","published_at":"2025-04-05T02:38:12.000Z","download_url":"https://codeload.github.com/lfreleng-actions/python-supported-versions-action/tar.gz/v0.1.2","html_url":"https://github.com/lfreleng-actions/python-supported-versions-action/releases/tag/v0.1.2","dependencies_parsed_at":"2025-07-21T05:11:39.613Z","dependency_job_id":null,"purl":"pkg:github/lfreleng-actions/python-supported-versions-action@v0.1.2","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.2","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.2/manifests"},{"name":"v0.1.1","sha":"4a13b86900547ed05d67e0332c4c6749f1391d85","kind":"tag","published_at":"2025-03-28T16:35:50.000Z","download_url":"https://codeload.github.com/lfreleng-actions/python-supported-versions-action/tar.gz/v0.1.1","html_url":"https://github.com/lfreleng-actions/python-supported-versions-action/releases/tag/v0.1.1","dependencies_parsed_at":"2025-07-21T05:11:34.631Z","dependency_job_id":null,"purl":"pkg:github/lfreleng-actions/python-supported-versions-action@v0.1.1","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.1","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.1/manifests"},{"name":"v0.1.0","sha":"2466ad0e7e119e5484bb404b84b97253c862991b","kind":"tag","published_at":"2025-03-16T14:23:49.000Z","download_url":"https://codeload.github.com/lfreleng-actions/python-supported-versions-action/tar.gz/v0.1.0","html_url":"https://github.com/lfreleng-actions/python-supported-versions-action/releases/tag/v0.1.0","dependencies_parsed_at":"2025-07-21T05:11:32.931Z","dependency_job_id":null,"purl":"pkg:github/lfreleng-actions/python-supported-versions-action@v0.1.0","tag_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.0","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/tags/v0.1.0/manifests"}]},"repo_metadata_updated_at":"2025-12-25T19:13:13.157Z","dependent_packages_count":0,"downloads":null,"downloads_period":null,"dependent_repos_count":0,"rankings":{"downloads":null,"dependent_repos_count":30.472652347652346,"dependent_packages_count":0.0,"stargazers_count":null,"forks_count":null,"docker_downloads_count":null,"average":15.236326173826173},"purl":"pkg:githubactions/lfreleng-actions/python-supported-versions-action","advisories":[],"docker_usage_url":"https://docker.ecosyste.ms/usage/actions/lfreleng-actions/python-supported-versions-action","docker_dependents_count":null,"docker_downloads_count":null,"usage_url":"https://repos.ecosyste.ms/usage/actions/lfreleng-actions/python-supported-versions-action","dependent_repositories_url":"https://repos.ecosyste.ms/api/v1/usage/actions/lfreleng-actions/python-supported-versions-action/dependencies","status":null,"funding_links":[],"critical":null,"issue_metadata":{"last_synced_at":"2025-12-22T21:06:16.743Z","issues_count":0,"pull_requests_count":53,"avg_time_to_close_issue":null,"avg_time_to_close_pull_request":60787.8,"issues_closed_count":0,"pull_requests_closed_count":40,"pull_request_authors_count":4,"issue_authors_count":0,"avg_comments_per_issue":null,"avg_comments_per_pull_request":0.09433962264150944,"merged_pull_requests_count":39,"bot_issues_count":0,"bot_pull_requests_count":36,"past_year_issues_count":0,"past_year_pull_requests_count":53,"past_year_avg_time_to_close_issue":null,"past_year_avg_time_to_close_pull_request":60787.8,"past_year_issues_closed_count":0,"past_year_pull_requests_closed_count":40,"past_year_pull_request_authors_count":4,"past_year_issue_authors_count":0,"past_year_avg_comments_per_issue":null,"past_year_avg_comments_per_pull_request":0.09433962264150944,"past_year_bot_issues_count":0,"past_year_bot_pull_requests_count":36,"past_year_merged_pull_requests_count":39,"issues_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfreleng-actions%2Fpython-supported-versions-action/issues","maintainers":[],"active_maintainers":[]},"versions_url":"https://packages.ecosyste.ms/api/v1/registries/github%20actions/packages/lfreleng-actions%2Fpython-supported-versions-action/versions","version_numbers_url":"https://packages.ecosyste.ms/api/v1/registries/github%20actions/packages/lfreleng-actions%2Fpython-supported-versions-action/version_numbers","dependent_packages_url":"https://packages.ecosyste.ms/api/v1/registries/github%20actions/packages/lfreleng-actions%2Fpython-supported-versions-action/dependent_packages","related_packages_url":"https://packages.ecosyste.ms/api/v1/registries/github%20actions/packages/lfreleng-actions%2Fpython-supported-versions-action/related_packages","codemeta_url":"https://packages.ecosyste.ms/api/v1/registries/github%20actions/packages/lfreleng-actions%2Fpython-supported-versions-action/codemeta","maintainers":[]}