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
11 changes: 9 additions & 2 deletions .github/workflows/sync-releases.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@ jobs:
sync-releases:
runs-on: ubuntu-latest
steps:
- name: Check team membership
if: github.event_name == 'workflow_dispatch'
uses: PrestaShop/.github/.github/actions/team-guard@master
with:
team_slug: prestashop-sa
token: ${{ secrets.JARVIS_TOKEN }}

- name: Checkout the repo
uses: actions/checkout@v2
uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: 3.9
- name: Install dependencies
Expand Down
76 changes: 51 additions & 25 deletions prestashop_docker/docker_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import requests
import ssl
import time
from urllib.parse import urljoin

logger = logging.getLogger(__name__)
ssl._create_default_https_context = ssl._create_unverified_context
Expand All @@ -21,7 +22,8 @@ def __init__(self, cache, debug):
@type debug: bool
"""
self.sleep_time = 1
self.url = 'https://hub.docker.com/v2/repositories/'
self.auth_url = 'https://auth.docker.io/token'
self.registry_url = 'https://registry-1.docker.io/v2/'
self.cache = cache
self.is_debug = debug

Expand All @@ -31,54 +33,78 @@ def __init__(self, cache, debug):
def get_tags(self, image_name):
"""Generate return tags

@return: The json content
@rtype: dict
The registry API is used instead of the Docker Hub one because
Docker Hub refuses to paginate large tag lists for anonymous
requests, while the registry returns them in a single response.

@param image_name: Name of the image (e.g. library/php)
@type image_name: str
@return: The tags, as a list of {'name': <tag>} dicts
@rtype: list
"""
logger.debug(
'Processing request for tags'
)

data = self.execute(
self.url + image_name + '/tags?page_size=100'
)
headers = {'Authorization': 'Bearer ' + self.get_token(image_name)}
request_url = self.registry_url + image_name + '/tags/list'

tags = []
while request_url is not None:
resp = self.execute(request_url, headers)
tags += resp.json()['tags']
if 'next' in resp.links:
request_url = urljoin(request_url, resp.links['next']['url'])
else:
request_url = None

return [{'name': name} for name in tags]

def get_token(self, image_name):
"""Get an anonymous pull token for the registry API

@param image_name: Name of the image the token grants access to
@type image_name: str
@return: The token
@rtype: str
"""
# Tokens are short-lived, never serve one from the cache
with requests_cache.disabled():
resp = self.execute(
self.auth_url + '?service=registry.docker.io&scope=repository:' + image_name + ':pull'
)

return data['results']
return resp.json()['token']

def execute(self, request_url):
def execute(self, request_url, headers=None):
"""Execute url

@param request_url: The url to execute
@param headers: Optional HTTP headers
@return: The HTTP Response
@rtype: dict
@rtype: requests.Response
"""
logger.debug(
'Execute URL: ' + request_url
)

resp = requests.get(
request_url
request_url,
headers=headers
)

data = resp.json()

if resp.status_code != 200:
# Something went wrong, retry
time.sleep(self.sleep_time)
DockerApi.retries += 1
if DockerApi.retries >= 10:
raise requests.HTTPError(resp.text)

return self.execute(request_url)
else:
DockerApi.retries = 0
# Data not in cache
if not hasattr(resp, 'from_cache') or not resp.from_cache:
time.sleep(self.sleep_time)

if 'next' in data and data['next'] is not None:
# Compute items if there is a next url
data['results'] += self.execute(
data['next']
)['results']
return data
return self.execute(request_url, headers)

DockerApi.retries = 0
# Data not in cache
if not hasattr(resp, 'from_cache') or not resp.from_cache:
time.sleep(self.sleep_time)

return resp
Loading