Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature update #20

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
9 changes: 9 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
=======
History
=======
0.0.9 (2023-08-21)
------------------
* Support DLRN results, local composes
* Allow et:: to look at one specific advisory instead of a release
* Allow skipping downgrades or upgrades
* Improve help output
* Allow specifying verify parameter to requests
* Allow multi-arch non-RPM builds when cleaning tags

0.0.8 (2020-09-10)
------------------
* Use argparse for tag-over
Expand Down
2 changes: 1 addition & 1 deletion PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tag_utils
Version: 0.0.7
Version: 0.0.9
Summary: Pungi/Koji tag utilities for Release Depot
Author: release-depot
Author-email: [email protected]
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

setup(
name='tag_utils',
version='0.0.8',
version='0.0.9',
install_requires=['pyyaml', 'koji', 'toolchest>=0.0.6', 'koji_wrapper'],
tests_require=TEST_REQUIRES,
extras_require={'test': TEST_REQUIRES,
Expand Down
1 change: 1 addition & 0 deletions tag_utils/cli/tag_delta.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def main():
'<koji_tag> | file:<filename> '
'| http[s]://<url to compose> '
'| et:<release name or id> (Errata Tool Release name or id) '
'| et::<id> (Single Errata Tool advisory id) '
'| - (use stdin as list of nvr to compare against)')

parser.add_argument('--new', action='store_true', default=False,
Expand Down
14 changes: 14 additions & 0 deletions tag_utils/compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ def check_compose(url, verify=True):
raise ValueError('Failed to check compose; HTTP code ' + str(ret.status_code))


def fetch_or_read(url):
if url.startswith('file://'):
filename = url[7:]
fp = open(filename, 'r')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: if you do this in a with block it will be more in keeping with current python idioms, and take care of the close for you. It would look like this:

with open(filename, 'r') as fp:
    ret = fp.read()

ret = fp.read()
fp.close()
return ret
else:
ret = requests.get(url)
if ret.status_code == 200:
return ret.text
raise ValueError('Failed to check compose; HTTP code ' + str(ret.status_code))


def fetch_rpm_metadata(url, verify=True):
check_compose(url)
full_url = os.path.join(url, 'compose/metadata/rpms.json')
Expand Down
44 changes: 40 additions & 4 deletions tag_utils/delta.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/usr/bin/env python

from urllib.parse import urlparse

import koji_wrapper
from koji_wrapper.base import KojiWrapperBase
from koji_wrapper.tag import KojiTag
Expand All @@ -9,7 +11,8 @@

from .basic import file_as_nevr
from .compose import compose_as_nevr
from .et import get_build_for_release
from .dlrn import json_api_as_nevr
from .et import get_build_for_release, get_build_for_advisory
from .koji import latest_tagged_as_nevr

__koji_session = None
Expand All @@ -29,6 +32,20 @@ def release_set_as_nevr(release_name_or_id, koji_session, **kwargs):
return get_build_for_release(release_name_or_id.strip('et:'), __koji_session)


def erratum_set_as_nevr(errata_id, koji_session, **kwargs):
global __koji_session

if 'session' in kwargs:
__koji_session = kwargs['session']

if __koji_session is None:
__koji_session = KojiWrapperBase(profile='brew')
if __koji_session is None:
raise Exception('Could not connect to koji')

return get_build_for_advisory(errata_id.strip('et::'), __koji_session)


def tag_to_latest_builds(tag, **kwargs):
global __koji_session
inherit = False
Expand All @@ -55,20 +72,39 @@ def tag_to_latest_builds(tag, **kwargs):
return latest_tagged_as_nevr(koji_tag)


def _url_as_nevr(inp):
parsed_url = urlparse(inp)

if not parsed_url.path:
raise ValueError('Invalid URL: ' + inp)

if parsed_url.path.startswith('/dlrn/versions/'):
# drln API (JSON) - preferred
ret = json_api_as_nevr(inp)
else:
# fetch compose data
ret = compose_as_nevr(inp)
return ret


# Automatically resolve input class to dict of:
# {'n': 'n-e:v-r', 'm': 'm-e:v-r'}
# Supports:
# - pungi compose
# - koji tag
# - flat file (list of NVRs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit missing trailing ")"

# - errata tool build lists
# - JSON-parsed DLRN results
def input_to_nevr_dict(inp, **kwargs):
ret = None

if isinstance(inp, str):
if ( inp.startswith('http://') or # NOQA
inp.startswith('https://') or # NOQA
inp.startswith('/')):
# fetch compose data
ret = compose_as_nevr(inp)
inp.startswith('file://')):
ret = _url_as_nevr(inp)
elif inp.startswith('et::'):
ret = erratum_set_as_nevr(inp, __koji_session, **kwargs)
elif inp.startswith('et:'):
ret = release_set_as_nevr(inp, __koji_session, **kwargs)
elif inp.startswith('file:'):
Expand Down
22 changes: 22 additions & 0 deletions tag_utils/dlrn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env python

import json

import requests


from .common import tidy_nevra


def fetch_json_data(url):
ret = requests.get(url)
if ret.status_code == 200:
return json.loads(ret.text)


def json_api_as_nevr(url):
md = fetch_json_data(url)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: can we use a more descriptive variable name here? Obviously 'md' is going to be the returned json, but maybe we could just spell out what this abbreviation is for, so it is more clear to readers?

ret = {}
for p in md['packages']:
ret[p['name']] = tidy_nevra(p['nvr'])
return ret
35 changes: 23 additions & 12 deletions tag_utils/et.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,7 @@ def get_advisory_list(errata_tool_release, debug=False):
return [Erratum(errata_id=advisory_id) for advisory_id in advisory_ids]


def get_build_for_release(release_name_or_id, koji_session, debug=False):
if debug:
print('got in "{0}"'.format(release_name_or_id))
try:
rel = errata_tool.release.Release(id=int(release_name_or_id))
advisories = [i for i in rel.advisories() if i["status"] not in ('SHIPPED_LIVE', 'DROP_NO_SHIP')]
advisory_list = [Erratum(errata_id=i['id']) for i in advisories]
if debug:
print("Got list of advisories:", advisories)
except ValueError:
advisory_list = get_advisory_list(release_name_or_id, debug=debug)

def _get_builds_for_advisory_list(advisory_list, koji_session, debug=False):
all_builds = set()
for advisory in advisory_list:
if debug:
Expand All @@ -61,3 +50,25 @@ def get_build_for_release(release_name_or_id, koji_session, debug=False):
return_data[build_data['name']] = koji_build_to_nevr(build_data)

return return_data


def get_build_for_release(release_name_or_id, koji_session, debug=False):
if debug:
print('got in "{0}"'.format(release_name_or_id))
try:
rel = errata_tool.release.Release(id=int(release_name_or_id))
advisories = [i for i in rel.advisories() if i["status"] not in ('SHIPPED_LIVE', 'DROP_NO_SHIP')]
advisory_list = [Erratum(errata_id=i['id']) for i in advisories]
if debug:
print("Got list of advisories:", advisories)
except ValueError:
advisory_list = get_advisory_list(release_name_or_id, debug=debug)

return _get_builds_for_advisory_list(advisory_list, koji_session, debug=debug)
Copy link
Member

@jguiditta jguiditta Sep 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a nice separation of chunks of functionality, and might be an ideal place for some of those tests @jpichon suggested.



def get_build_for_advisory(advisory_id, koji_session, debug=False):
if debug:
print('got advisory "{0}"'.format(advisory_id))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flake8 is failing here - a prior version of this patch had .format(errata_id), which was wrong, but it should be passing on this here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, no, I just received notification from prior versions in email. This version is fine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (non-blocking): you might consider using f-strings like we do in most of our other code, we have found them to be a nice readabilty improvement over the older .format style. So this would become:

print(f"got advisory {advisory_id}")

erratum = Erratum(errata_id=advisory_id)
return _get_builds_for_advisory_list([erratum], koji_session, debug=debug)