fix: handle urls without release id format (#3306)

Sometimes when users customize the URLs for release, they use urls that
don't have
the same format the python-build-standalone URLs. Namely, they may not
have
the release_id component of the url. This would result in an error
parsing such
urls.

To fix, refine the url parsing to check if a component is a valid
numeric release id.

Fixes https://github.com/bazel-contrib/rules_python/issues/3285
diff --git a/python/versions.bzl b/python/versions.bzl
index 30929f8..34cffc5 100644
--- a/python/versions.bzl
+++ b/python/versions.bzl
@@ -1045,7 +1045,12 @@
     for u in url:
         p, _, _ = platform.partition(FREETHREADED)
 
-        release_id = int(u.split("/")[-2])
+        # Assume an unknown release_id is a newer url format
+        release_id = 99999999
+        url_parts = u.split("/")
+        if len(url_parts) >= 2 and url_parts[-2].isdigit():
+            maybe_release_id = url_parts[-2]
+            release_id = int(maybe_release_id)
 
         if FREETHREADED.lstrip("-") in platform:
             build = "{}+{}-full".format(
diff --git a/tests/get_release_info/BUILD.bazel b/tests/get_release_info/BUILD.bazel
new file mode 100644
index 0000000..26517e6
--- /dev/null
+++ b/tests/get_release_info/BUILD.bazel
@@ -0,0 +1,24 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+load(":get_release_info_tests.bzl", "get_release_info_test_suite")
+
+package(
+    default_testonly = True,
+    default_visibility = ["//:__subpackages__"],
+)
+
+licenses(["notice"])
+
+get_release_info_test_suite(name = "get_release_info")
diff --git a/tests/get_release_info/get_release_info_tests.bzl b/tests/get_release_info/get_release_info_tests.bzl
new file mode 100644
index 0000000..ca553a3
--- /dev/null
+++ b/tests/get_release_info/get_release_info_tests.bzl
@@ -0,0 +1,56 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Tests for get_release_info."""
+
+load("@rules_testing//lib:test_suite.bzl", "test_suite")
+load("//python:versions.bzl", "get_release_info")  # buildifier: disable=bzl-visibility
+
+_tests = []
+
+def _test_file_url(env):
+    """Tests that a file:/// url is handled correctly."""
+    tool_versions = {
+        "3.11.5": {
+            "sha256": {
+                "x86_64-unknown-linux-gnu": "fbed6f7694b2faae5d7c401a856219c945397f772eea5ca50c6eb825cbc9d1e1",
+            },
+            "strip_prefix": "python",
+            "url": "file:///tmp/cpython-3.11.5.tar.gz",
+        },
+    }
+
+    expected_url = "file:///tmp/cpython-3.11.5.tar.gz"
+    expected_filename = "file:///tmp/cpython-3.11.5.tar.gz"
+
+    filename, urls, strip_prefix, patches, patch_strip = get_release_info(
+        platform = "x86_64-unknown-linux-gnu",
+        python_version = "3.11.5",
+        tool_versions = tool_versions,
+    )
+
+    env.expect.that_str(filename).equals(expected_filename)
+    env.expect.that_collection(urls).contains_exactly([expected_url])
+    env.expect.that_str(strip_prefix).equals("python")
+    env.expect.that_collection(patches).has_size(0)
+    env.expect.that_bool(patch_strip == None).equals(True)
+
+_tests.append(_test_file_url)
+
+def get_release_info_test_suite(name):
+    """Defines the test suite for get_release_info."""
+    test_suite(
+        name = name,
+        basic_tests = _tests,
+    )