oss-fuzz/infra/cifuzz/filestore/github_actions/github_api.py

109 lines
3.5 KiB
Python

# Copyright 2021 Google LLC
#
# 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.
"""Module for dealing with the GitHub API. This is different from
github_actions_toolkit which only deals with the actions API. We need to use
both."""
import logging
import os
import sys
import requests
import filestore
# pylint: disable=wrong-import-position,import-error
sys.path.append(
os.path.join(__file__, os.path.pardir, os.path.pardir, os.path.pardir,
os.path.pardir))
import retry
_MAX_ITEMS_PER_PAGE = 100
_GET_ATTEMPTS = 3
_GET_BACKOFF = 1
def get_http_auth_headers(config):
"""Returns HTTP headers for authentication to the API."""
authorization = f'token {config.token}'
return {
'Authorization': authorization,
'Accept': 'application/vnd.github.v3+json'
}
def _get_artifacts_list_api_url(repo_owner, repo_name):
"""Returns the artifacts_api_url for |repo_name| owned by |repo_owner|."""
return (f'https://api.github.com/repos/{repo_owner}/'
f'{repo_name}/actions/artifacts')
@retry.wrap(_GET_ATTEMPTS, _GET_BACKOFF)
def _do_get_request(*args, **kwargs):
"""Wrapped version of requests.get that does retries."""
return requests.get(*args, **kwargs)
def _get_items(url, headers):
"""Generator that gets and yields items from a GitHub API endpoint (specified
by |URL|) sending |headers| with the get request."""
# Github API response pages are 1-indexed.
page_counter = 1
# Set to infinity so we run loop at least once.
total_num_items = float('inf')
item_num = 0
while item_num < total_num_items:
params = {'per_page': _MAX_ITEMS_PER_PAGE, 'page': str(page_counter)}
response = _do_get_request(url, params=params, headers=headers)
response_json = response.json()
if not response.status_code == 200:
# Check that request was successful.
logging.error('Request to %s failed. Code: %d. Response: %s',
response.request.url, response.status_code, response_json)
raise filestore.FilestoreError('Github API request failed.')
if total_num_items == float('inf'):
# Set proper total_num_items
total_num_items = response_json['total_count']
# Get the key for the items we are after.
keys = [key for key in response_json.keys() if key != 'total_count']
assert len(keys) == 1, keys
items_key = keys[0]
for item in response_json[items_key]:
yield item
item_num += 1
page_counter += 1
def find_artifact(artifact_name, artifacts):
"""Find the artifact with the name |artifact_name| in |artifacts|."""
for artifact in artifacts:
# TODO(metzman): Handle multiple by making sure we download the latest.
if artifact['name'] == artifact_name and not artifact['expired']:
return artifact
return None
def list_artifacts(owner, repo, headers):
"""Returns a generator of all the artifacts for |owner|/|repo|."""
url = _get_artifacts_list_api_url(owner, repo)
logging.debug('Getting artifacts from: %s', url)
return _get_items(url, headers)