Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ jobs:
run: |
FORCE=$(if git log --pretty=format:"%s" HEAD^..HEAD | grep -q '\[force\]'; then echo "--force"; else echo ""; fi)
uv run dpn $FORCE build-matrix --event ${{ github.event_name }}
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_PUBLIC_TOKEN: ${{ secrets.DOCKERHUB_PUBLIC_TOKEN }}


deploy:
Expand Down
27 changes: 25 additions & 2 deletions src/docker_python_nodejs/docker_hub.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from typing import TypedDict

import requests
Expand Down Expand Up @@ -43,15 +44,37 @@ class DockerTagResponse(TypedDict):
results: list[DockerTagDict]


def fetch_tags(package: str, page: int = 1) -> list[DockerTagDict]:
class DockerCreateAccessTokenResponse(TypedDict):
access_token: str


def token_auth() -> str:
"""Return a short lived access token for Docker Hub authentication. Expires in 10min"""
user = os.getenv("DOCKERHUB_USERNAME", "")
token = os.getenv("DOCKERHUB_PUBLIC_TOKEN", "")
if not user or not token:
return ""

res = requests.post(
"https://hub.docker.com/v2/auth/token",
json={"identifier": user, "secret": token},
timeout=10.0,
)
res.raise_for_status()
data: DockerCreateAccessTokenResponse = res.json()
return data["access_token"]


def fetch_tags(package: str, token_auth: str, page: int = 1) -> list[DockerTagDict]:
"""Fetch available docker tags."""
result = requests.get(
f"https://registry.hub.docker.com/v2/namespaces/library/repositories/{package}/tags",
params={"page": page, "page_size": 100},
headers={"Authorization": f"Bearer {token_auth}"} if token_auth else None,
timeout=10.0,
)
result.raise_for_status()
data: DockerTagResponse = result.json()
if not data["next"]:
return data["results"]
return data["results"] + fetch_tags(package, page=page + 1)
return data["results"] + fetch_tags(package, token_auth, page=page + 1)
5 changes: 3 additions & 2 deletions src/docker_python_nodejs/versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from docker_python_nodejs.readme import format_supported_versions

from .docker_hub import DockerImageDict, DockerTagDict, fetch_tags
from .docker_hub import DockerImageDict, DockerTagDict, fetch_tags, token_auth
from .nodejs_versions import (
fetch_node_releases,
fetch_node_unofficial_releases,
Expand Down Expand Up @@ -129,7 +129,8 @@ def decide_python_versions(distros: list[str], supported_versions: list[Supporte

# FIXME: can we avoid enumerating all tags to speed up things?
logger.debug("Fetching tags for python")
tags = [tag for tag in fetch_tags("python") if python_wanted_tag_pattern.match(tag["name"])]
docker_auth = token_auth()
tags = [tag for tag in fetch_tags("python", token_auth=docker_auth) if python_wanted_tag_pattern.match(tag["name"])]

versions: list[PythonVersion] = []
for supported_version in supported_versions:
Expand Down