Add relevant releases tooling into the repo

This patch adds refactored releasing tooling from [1] to the "mainlined"
repository for general usage.

[1] https://github.com/noonedeadpunk/osa_cli_releases/tree/standalone

Change-Id: I486de0edfa6f07b960069ec99f60effefd157f11
Signed-off-by: Dmitriy Rabotyagov <dmitriy.rabotyagov@cleura.com>
This commit is contained in:
Dmitriy Rabotyagov
2025-08-12 12:52:23 +02:00
parent 80cbc471c8
commit b625fc41f0
11 changed files with 5788 additions and 14 deletions

View File

@@ -22,26 +22,24 @@ necessary for releasing into the openstack-ansible code tree. This
allowed the tooling for releasing to be more flexible,
and lighter, over time.
Now, all the functions are separated, and included into a branch
independent tooling, `osa_cli_releases`.
All the functions are separated, and included as an extra console
script ``openstack-ansible-releases``.
.. _osa_cli_releases: https://github.com/noonedeadpunk/osa_cli_releases
You can install the latest version of this tooling by running:
By default, dependencies for the script are not installed to minimize amount
of them for regular users.
To ensure all required dependencies are installed for the script, you can run:
.. parsed-literal::
pip3 install -e git+https://github.com/noonedeadpunk/osa-cli.git#egg=openstack_ansible_cli
pip3 install -e git+https://github.com/noonedeadpunk/osa_cli_releases.git#egg=osa_cli_releases
pip3 install -e git+https://opendev.org/openstack/openstack-ansible#egg=openstack-ansible[releases]
This tooling can then be called using ``osa releases``.
Each subcommand contains help by default.
Updating upstream SHAs
----------------------
The dependencies for OpenStack-Ansible are updated
through the use of ``osa releases bump_upstream_shas``. This script
through the use of ``openstack-ansible-releases bump_upstream_shas``. This script
updates the project's pinned SHAs, located in the
``inventory/group_vars/<service_group>/source_git.yml`` file,
based on their ``_git_track_branch`` value.
@@ -51,7 +49,7 @@ Updating OpenStack-Ansible roles
--------------------------------
Updating the roles to their latest version per branch is done through
``osa releases bump_roles``.
``openstack-ansible-releases bump_roles``.
This can do multiple things:
@@ -61,13 +59,13 @@ This can do multiple things:
* Unfreeze of master.
Master doesn't get frozen, unless explicitly asked for it for release
milestones, using the command ``osa releases freeze_roles_for_milestone``
milestones, using the command ``openstack-ansible-releases freeze_roles_for_milestone``
Updating required collections
-----------------------------
Updating collections to their latest version is done through
``osa releases bump_collections``.
``openstack-ansible-releases bump_collections``.
Please note, that only collections with type `git` are supported.
Ones, that are installed from Ansible Galaxy should be bumped manually.
@@ -77,7 +75,7 @@ Check current pins status
-------------------------
You can check the current PyPI pins that are used in openstack-ansible
repository by running ``osa releases check_pins``. This will display
repository by running ``openstack-ansible-releases check_pins``. This will display
a table, showing the current pin in OSA, and what is available upstream on
PyPI.

File diff suppressed because it is too large Load Diff

657
osa_toolkit/releasing.py Normal file
View File

@@ -0,0 +1,657 @@
import argparse
import glob
import json
import os
import re
import shutil
import subprocess
import tempfile
import urllib.request
from datetime import datetime, timedelta
try:
from git import Repo
from jinja2 import Template as j2_template
from packaging import requirements as pyrequirements
from packaging import version
from prettytable import PrettyTable # prettytable
from ruamel.yaml import YAML # ruamel.yaml
except ImportError as err:
raise SystemExit(
'Required dependencies are missing for this script! '
'Please, make sure that OpenStack-Ansible is installed with '
'`releases` extras.\n'
'Check docs for more details: https://docs.openstack.org/openstack-ansible/latest/contributors/periodic-work.html#osa-cli-tooling \n\n'
f'Error: {err}'
)
BASE_URI_MAPPING = {
'openstack_opendev_base_url': 'https://opendev.org',
'openstack_github_base_url': 'https://github.com',
}
def _update_head_date(data):
"""Parse data and update date of last bump in it
:param data: String to parse for
:returns: string with current date instead of old one
"""
return re.sub(
r'### HEAD as of [0-9.]{10} ###',
"### HEAD as of {:%d.%m.%Y} ###".format(datetime.now()),
data)
def parse_args():
parser = argparse.ArgumentParser(
description="Tooling for releasing OpenStack-Ansible"
)
subparsers = parser.add_subparsers(help='subcommand help')
# check_pins
check_pins_parser = subparsers.add_parser(
'check_pins',
help='Sha used for fetching the upper constraints file in requirements'
)
check_pins_parser.add_argument(
"--requirements_sha",
help="Sha used for fetching the upper constraints file in requirements",
)
check_pins_parser.add_argument(
"--file",
help="path to global requirements pin file",
default="global-requirement-pins.txt",
)
check_pins_parser.set_defaults(func=analyse_global_requirement_pins)
# bump_upstream_shas
bump_upstream_shas_parser = subparsers.add_parser(
'bump_upstream_shas',
help='Bump SHAs of OpenStack services'
)
bump_upstream_shas_parser.add_argument(
"--path",
action='append',
help="glob expressions for finding files that contain SHAs",
default=["playbooks/defaults/repo_packages/*.yml",
"inventory/group_vars/*all/*_git.yml"],
)
bump_upstream_shas_parser.set_defaults(func=bump_ushas)
# bump_collections
bump_collections_parser = subparsers.add_parser(
'bump_collections',
help='Bump version of Ansible collections'
)
bump_collections_parser.add_argument(
"--file",
help="path to ansible-collection-requirements.yml file",
default="ansible-collection-requirements.yml",
)
bump_collections_parser.set_defaults(func=bump_acr)
# bump_roles
bump_roles_parser = subparsers.add_parser(
'bump_roles',
help='Bump roles SHA and copies releases notes from the openstack roles.'
)
bump_roles_parser.add_argument(
"--file",
help="path to ansible-role-requirements.yml file",
default="ansible-role-requirements.yml",
)
bump_roles_parser.set_defaults(func=bump_arr)
# freeze_roles_for_milestone
freeze_roles_parser = subparsers.add_parser(
'freeze_roles_for_milestone',
help='Freeze all roles shas for milestone releases and copy release notes'
)
freeze_roles_parser.add_argument(
"--file",
help="path to ansible-role-requirements.yml file",
default="ansible-role-requirements.yml",
)
freeze_roles_parser.set_defaults(func=freeze_arr)
# unfreeze_roles_from_milestone
unfreeze_roles_parser = subparsers.add_parser(
'unfreeze_roles_from_milestone',
help=' Unfreeze all roles shas after milestone release'
)
unfreeze_roles_parser.add_argument(
"--file",
help="path to ansible-role-requirements.yml file",
default="ansible-role-requirements.yml",
)
freeze_roles_parser.set_defaults(func=unfreeze_arr)
return parser.parse_args()
def analyse_global_requirement_pins(args):
"""Check a package list file for updates on PyPI or on upper constraints"""
with open(args.file, "r") as global_req_file:
pins = {
pin.name: pin.specifier
for pin in parse_requirements(global_req_file.read())
}
latest_versions = get_pypi_versions(pins.keys())
if not args.requirements_sha:
sha = discover_requirements_sha()
else:
sha = args.requirements_sha
url = f"https://raw.githubusercontent.com/openstack/requirements/{sha}/upper-constraints.txt"
with urllib.request.urlopen(url) as response:
constraints_versions = {
pin.name: pin.specifier for pin in parse_requirements(response.read().decode('utf-8'))
}
print_requirements_state(pins, latest_versions, constraints_versions)
def parse_requirements(requirements):
"""Parse requirement file contents into name, constraints specs, and extra data
:param pin: Complete string containing a requirement
:returns: A detailed requirement, each requirement being a tuple containing:
- package 'name' (string)
- package 'specs' (list of tuples)
- package 'extras' (list)
"""
for req in requirements.split('\n'):
if re.match(r'^#\s*\w.*', req):
continue
try:
yield pyrequirements.Requirement(req)
except pyrequirements.InvalidRequirement:
continue
def get_pypi_versions(pins):
""" Display package metadata on PyPI
:param pins: this is a list of packages to check on PyPI
:returns: dict whose keys are package names and value is latest package version)
"""
versions = {}
for pkgname in pins:
versions[pkgname] = get_pypi_version(pkgname)
return versions
def get_pypi_version(name):
""" Return latest version of a package on PyPI
:param name: This is the project name on PyPI
:returns: String containing latest version of package
"""
with urllib.request.urlopen(f"https://pypi.org/pypi/{name}/json") as url:
data = json.load(url)
return data["info"]["version"]
def discover_requirements_sha(
path="inventory/group_vars/all/source_git.yml"
):
""" Finds in openstack-ansible repos the current SHA for the requirements repo
:param path: Location of the YAML file containing requirements_git_install_branch
:returns: String containing the SHA of the requirements repo.
"""
yaml = YAML() # use ruamel.yaml to keep comments
with open(path, "r") as os_repos_yaml:
repos = yaml.load(os_repos_yaml)
return repos["requirements_git_install_branch"]
def print_requirements_state(pins, latest_versions, constraints_versions):
""" Shows current status of global-requirement-pins.txt
:param pins: A dict containing requirements of the current global-requirement-pins file
:param latest_versions: A dict containing the latest version of each requirement in pypi
:param constraints_version: A dict containing the current version of all constraints from requirements repo
:returns: Nothing
"""
table = PrettyTable(
["Package", "Current Version Spec", "Latest version on PyPI", "Constrained to"]
)
for pkgname in pins.keys():
table.add_row(
[
pkgname,
pins[pkgname],
latest_versions[pkgname],
constraints_versions.get(pkgname, "None"),
]
)
print(table)
def bump_upstream_repos_shas(path):
""" Processes all the yaml files in the path by updating their upstream repos shas
:param path: String containing the location of the yaml files to update
:returns: None
"""
filelist = find_yaml_files(path)
for filename in filelist:
print("Working on %s" % filename)
bump_upstream_repos_sha_file(filename)
def find_yaml_files(paths):
""" Lists all the files in a provided paths
:param paths: Folder location
:returns: List of files matching the glob
"""
found_files = [
file
for path in paths
for file in glob.glob(path)
]
return found_files
def bump_upstream_repos_sha_file(filename):
yaml = YAML() # use ruamel.yaml to keep comments
yaml.preserve_quotes = True
with open(filename, "r") as ossyml:
yml_data = ossyml.read()
repofiledata = yaml.load(_update_head_date(yml_data))
repos = build_repos_dict(repofiledata)
changed = False
for project, projectdata in repos.items():
# a _git_track_branch string of "None" means no tracking, which means
# do not update (as there is no branch to track)
project_url = j2_template(projectdata["url"]).render(BASE_URI_MAPPING)
if projectdata["trackbranch"] != "None":
print(
"Bumping project %s on its %s branch"
% (project_url, projectdata["trackbranch"])
)
sha = get_sha_from_ref(project_url, projectdata["trackbranch"])
if repofiledata[project + "_git_install_branch"] != sha:
repofiledata[project + "_git_install_branch"] = sha
changed = True
else:
print(
"Skipping project %s branch %s"
% (project_url, projectdata["trackbranch"])
)
if changed:
with open(filename, "w") as fw:
# Temporarily revert the explicit start to add --- into first line
yaml.explicit_start = True
yaml.dump(repofiledata, fw)
yaml.explicit_start = False
# def parse_repos_info(filename):
# """ Take a file consisting of ordered entries
# *_git_repo, followed by *_git_install_branch, with a comment the branch to track,
# returns information about each repos.
# :param filename: String containing path to file to analyse
# :returns: YAMLMap object, an ordered dict keeping the comments.
# """
# yaml = YAML() # use ruamel.yaml to keep comments
# with open(filename,'r') as ossyml:
# y = yaml.load(ossyml)
# return y
def build_repos_dict(repofiledict):
""" Returns a structured dict of repos data
:param repofiledict:
:returns: Dict of repos, whose values are dicts containing shas and branches.
"""
repos = dict()
reponames = [
key.replace("_git_repo", "")
for key in repofiledict.keys()
if key.endswith("_git_repo")
]
for reponame in reponames:
repos[reponame] = {
"url": repofiledict[reponame + "_git_repo"],
"sha": repofiledict[reponame + "_git_install_branch"],
"trackbranch": repofiledict[reponame + "_git_track_branch"],
}
return repos
def get_sha_from_ref(repo_url, reference):
""" Returns the sha corresponding to the reference for a repo
:param repo_url: location of the git repository
:param reference: reference of the branch
:returns: utf-8 encoded string of the SHA found by the git command
"""
# Using subprocess instead of convoluted git libraries.
# Any rc != 0 will be throwing an exception, so we don't have to care
out = subprocess.check_output(
["git", "ls-remote", "--exit-code", repo_url, reference]
)
# out is a b'' type string always finishing up with a newline
# construct list of (ref,sha)
refs = [
(line.split(b"\t")[1], line.split(b"\t")[0])
for line in out.split(b"\n")
if line != b"" and b"^{}" not in line
]
if len(refs) > 1:
raise ValueError(
"More than one ref for reference %s, please be more explicit %s"
% (reference, refs)
)
return refs[0][1].decode("utf-8")
def freeze_ansible_role_requirements_file(filename=""):
""" Freezes a-r-r for master"""
update_ansible_role_requirements_file(
filename, milestone_freeze=True
)
def unfreeze_ansible_role_requirements_file(filename=""):
""" Freezes a-r-r for master"""
update_ansible_role_requirements_file(
filename, milestone_unfreeze=True
)
def update_ansible_role_requirements_file(
filename="", milestone_freeze=False, milestone_unfreeze=False
):
""" Updates the SHA of each of the ansible roles based on branch given in argument
Do not do anything on master except if milestone_freeze.
In that case, freeze by using the branch present in version.
Else, stable branches only get openstack roles bumped.
Copies all the release notes of the roles at the same time.
"""
openstack_roles, external_roles, all_roles = sort_roles(filename)
clone_root_path = tempfile.mkdtemp()
for role in all_roles:
trackbranch = role.get("trackbranch")
if not trackbranch or trackbranch.lower() == "none":
print(
"Skipping role %s branch" % role["name"]
)
continue
copyreleasenotes = False
shallow_since = role.get("shallow_since")
# We don't want to copy config_template renos even if it's an openstack
# role, as it's not branched the same way.
if role in openstack_roles and (not role["src"].endswith("config_template")):
copyreleasenotes = True
# Freeze sha by checking its trackbranch value
# Do not freeze sha if trackbranch is None
if trackbranch:
try:
role_repo = clone_role(
role["src"], clone_root_path, branch=trackbranch, depth="1"
)
if milestone_unfreeze:
print(f"Unfreeze {trackbranch} role")
role["version"] = trackbranch
# Do nothing when trackbranch and version are same and not freezing
elif trackbranch == role.get("version") and not milestone_freeze:
print("Version and trackbranch equal, skipping...")
pass
# Freeze or Bump
else:
role_head = role_repo.head.object
role["version"] = str(role_head)
print(f"Bumped role {role['name']} to sha {role['version']}")
if shallow_since:
head_timestamp = role_head.committed_datetime
head_datetime = head_timestamp - timedelta(days=1)
role["shallow_since"] = head_datetime.strftime('%Y-%m-%d')
# Copy the release notes `Also handle the release notes
# If frozen, no need to copy release notes.
if copyreleasenotes:
print("Copying %s's release notes" % role["name"])
copy_role_releasenotes(role_repo.working_dir, "./")
finally:
shutil.rmtree(role_repo.working_dir)
shutil.rmtree(clone_root_path)
print("Overwriting ansible-role-requirements")
with open(filename, "w") as arryml:
yaml = YAML() # use ruamel.yaml to keep comments that could appear
yaml.explicit_start = True
yaml.dump(all_roles, arryml)
yaml.explicit_start = False
def update_ansible_collection_requirements(filename=''):
clone_root_path = tempfile.mkdtemp()
yaml = YAML() # use ruamel.yaml to keep comments
with open(filename, "r") as arryml:
yaml_data = arryml.read()
all_requirements = yaml.load(_update_head_date(yaml_data))
all_collections = all_requirements.get('collections')
for collection in all_collections:
collection_type = collection.get('type')
if collection_type == 'git' and collection["version"] != 'master':
collection_repo = clone_role(
collection["source"], clone_root_path
)
collection_tags = collection_repo.tags
collection_versions = list()
for tag in collection_tags:
try:
collection_versions.append(version.parse(tag.name))
except version.InvalidVersion:
continue
collection['version'] = str(max(collection_versions))
all_requirements['collections'] = all_collections
print("Overwriting ansible-collection-requirements")
with open(filename, "w") as arryml:
yaml = YAML() # use ruamel.yaml to keep comments that could appear
yaml.explicit_start = True
yaml.dump(all_requirements, arryml)
yaml.explicit_start = False
def sort_roles(ansible_role_requirements_file):
""" Separate the openstack roles from the external roles
:param ansible_role_requirements_file: Path to the a-r-r file
:returns: 3-tuple: (list of openstack roles, list of external roles, list of all roles)
"""
yaml = YAML() # use ruamel.yaml to keep comments
with open(ansible_role_requirements_file, "r") as arryml:
yaml_data = arryml.read()
all_roles = yaml.load(_update_head_date(yaml_data))
external_roles = []
openstack_roles = []
for role in all_roles:
if role["src"].startswith("https://git.openstack.org/") or (
role["src"].startswith("https://opendev.org/openstack/")
):
openstack_roles.append(role)
else:
external_roles.append(role)
return openstack_roles, external_roles, all_roles
def clone_role(url, clone_root_path, branch=None, clone_folder=None, depth=None):
""" Git clone
:param url: Source of the git repo
:param branch: Branch of the git repo
:param clone_root_path: The main folder in which the repo will be cloned.
:param clone_folder: The relative folder name of the git clone to the clone_root_path
:param depth(str): The git shallow clone depth
:returns: dulwich repository object
"""
gitargs = {}
if depth and depth.isdigit():
gitargs.update({"depth": depth, "no-single-branch": True})
if branch:
gitargs.update({"branch": branch})
if not clone_folder:
clone_folder = url.split("/")[-1]
dirpath = os.path.join(clone_root_path, clone_folder)
print(f'Clonning {url} to {dirpath}')
repo = Repo.clone_from(url, dirpath, **gitargs)
return repo
def copy_role_releasenotes(src_path, dest_path):
""" Copy release notes from src to dest
"""
renos = glob.glob("{}/releasenotes/notes/*.yaml".format(src_path))
for reno in renos:
subprocess.call(
["rsync", "-aq", reno, "{}/releasenotes/notes/".format(dest_path)]
)
def find_release_number():
""" Find a release version amongst usual OSA files
:returns: version (str), filename containing version (string)
"""
yaml = YAML() # use ruamel.yaml to keep comments
oa_version_files = [
"inventory/group_vars/all/all.yml",
"group_vars/all/all.yml",
"playbooks/inventory/group_vars/all.yml",
]
for filename in oa_version_files:
try:
with open(filename, "r") as vf:
version = yaml.load(vf)["openstack_release"]
found_file = filename
break
except FileNotFoundError:
pass
else:
raise FileNotFoundError("No file found matching the list of files")
return version, found_file
def next_release_number(current_version, releasetype):
version = current_version.split(".")
if releasetype in ("milestone", "rc"):
return increment_milestone_version(version, releasetype)
else:
increment = {"bugfix": (0, 0, 1), "feature": (0, 1, 0)}[releasetype]
return increment_version(version, increment)
# THis is taken from releases repo
def increment_version(old_version, increment):
"""Compute the new version based on the previous value.
:param old_version: Parts of the version string for the last
release.
:type old_version: list(str)
:param increment: Which positions to increment.
:type increment: tuple(int)
"""
new_version_parts = []
clear = False
for cur, inc in zip(old_version, increment):
if clear:
new_version_parts.append("0")
else:
new_version_parts.append(str(int(cur) + inc))
if inc:
clear = True
return new_version_parts
# THis is taken from releases repo
def increment_milestone_version(old_version, release_type):
"""Increment a version using the rules for milestone projects.
:param old_version: Parts of the version string for the last
release.
:type old_version: list(str)
:param release_type: Either ``'milestone'`` or ``'rc'``.
:type release_type: str
"""
if release_type == "milestone":
if "b" in old_version[-1]:
# Not the first milestone
new_version_parts = old_version[:-1]
next_milestone = int(old_version[-1][2:]) + 1
new_version_parts.append("0b{}".format(next_milestone))
else:
new_version_parts = increment_version(old_version, (1, 0, 0))
new_version_parts.append("0b1")
elif release_type == "rc":
new_version_parts = old_version[:-1]
if "b" in old_version[-1]:
# First RC
new_version_parts.append("0rc1")
else:
next_rc = int(old_version[-1][3:]) + 1
new_version_parts.append("0rc{}".format(next_rc))
else:
raise ValueError("Unknown release type {!r}".format(release_type))
return new_version_parts
def bump_ushas(args):
""" Bump upstream projects SHAs.
:param path: String containing the path of the YAML files formatted for updates
"""
bump_upstream_repos_shas(args.path)
def bump_acr(args):
""" Bump collection versions.
"""
update_ansible_collection_requirements(filename=args.file)
def bump_arr(args):
""" Bump roles SHA and copies releases notes from the openstack roles.
Also bumps roles from external sources when the branch to bump is master.
"""
update_ansible_role_requirements_file(filename=args.file)
def freeze_arr(args):
""" Freeze all roles shas for milestone releases.
Bump roles SHA and copies releases notes from the openstack roles.
Also freezes roles from external sources.
"""
freeze_ansible_role_requirements_file(filename=args.file)
def unfreeze_arr(args):
""" Unfreeze all roles shas for milestone releases.
Also unfreezes roles from external sources.
"""
unfreeze_ansible_role_requirements_file(filename=args.file)
def main():
args = parse_args()
args.func(args)
if __name__ == "__main__":
main()

View File

@@ -26,7 +26,13 @@ universal = 1
[files]
packages = osa_toolkit
[entry_points]
[options.extras_require]
releases =
ruamel.yaml
Jinja2
[options.entry_points]
console_scripts =
openstack-ansible-inventory = osa_toolkit.generate:main
openstack-ansible-inventory-manage = osa_toolkit.manage:main
openstack-ansible-releases = osa_toolkit.releasing:main [releases]

View File

@@ -20,3 +20,6 @@ jmespath>=1.0.0 # MIT
molecule==24.12.0 # MIT
molecule-plugins[docker]==23.6.0 # MIT
setuptools>75.0.0 # MIT
# Requirements for releases script
ruamel.yaml>=0.18 # MIT

View File

@@ -0,0 +1,196 @@
- name: ansible-hardening
scm: git
src: https://git.openstack.org/openstack/ansible-hardening
version: ac92973e1393cedf336ed4e295005c08c1a083e0
- name: apt_package_pinning
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-apt_package_pinning
version: 36b1161e8e76a76681bac089396a9e89056524d9
- name: pip_install
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-pip_install
version: 4f82d736d3546275bad1041ea832b8d599f84fd1
- name: galera_client
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-galera_client
version: a657d2289d9974335e18a5769b784e1860ede32b
- name: galera_server
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-galera_server
version: 94859aa149c659db66f240c0f292b92399f92171
- name: ceph_client
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-ceph_client
version: 20c2776760627a343c7ac717b226ac410cf998cb
- name: haproxy_server
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-haproxy_server
version: 57508dde05b3908a160fd6fcd40a6a69f96e90c6
- name: keepalived
scm: git
src: https://github.com/evrardjp/ansible-keepalived
version: 2b4a1f36c29b06b832bc4e6d112ca5559a98fd4a
- name: lxc_container_create
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-lxc_container_create
version: 3ff8b4c604be5794827941381a399ea3d0110bf2
- name: lxc_hosts
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-lxc_hosts
version: b9fad5c1dafa27ef2585bed170119d0f8623bea4
- name: memcached_server
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-memcached_server
version: 82e376f2e9547f35ebfaafad88abce74b9392b73
- name: openstack_hosts
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-openstack_hosts
version: 40c1e84c87e75cdcbf5b3603a907eb04c3fa452f
- name: os_keystone
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_keystone
version: faae9f6696c03c0fbb4782eb5303885e96ec8aa7
- name: openstack_openrc
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-openstack_openrc
version: f29df23e4a121c067769bbed17b8ca67612de8d4
- name: os_aodh
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_aodh
version: 312e94e000132444ca01878a4f24d9d2ad0fe725
- name: os_barbican
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_barbican
version: f3db3d834e9c1718e77cd73ff6b75a54b359d87a
- name: os_ceilometer
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_ceilometer
version: b9a235c748f6fbaca74c33baf89da2cccf04a7c4
- name: os_cinder
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_cinder
version: 94902df33aa8d55f9b655bc35da168b096eb374f
- name: os_designate
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_designate
version: 3d4280b8b82a6492ac4bfea835119442e804a55e
- name: os_glance
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_glance
version: 971403b6d99161329d2f1ac71e416c566a9cce6e
- name: os_gnocchi
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_gnocchi
version: 5e0d08213ca0e0a2a31dfbaa75b6243e3aa9b99b
- name: os_heat
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_heat
version: d60077fba13ef8d199810d9a030acf416d9e10cb
- name: os_horizon
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_horizon
version: 0654b3847f7e74f817dfb64a9ac9a5b0ee3f3bb9
- name: os_ironic
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_ironic
version: 1508e3731a69f7ef37aa2e7a1a2ee13290babee5
- name: os_magnum
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_magnum
version: 8631188013df183b119767c1b1958561cee47711
- name: os_molteniron
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_molteniron
version: f4ebd7ef37c8f9e8b46f591c9de6cf0888df1135
- name: os_neutron
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_neutron
version: 39d00bbc0d546e6e74c3183b2d401947572f1d44
- name: os_nova
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_nova
version: d0cc02fc82af1d6230ddcf8eb35f90671f40528a
- name: os_octavia
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_octavia
version: bffc1f6a8db60a168b9097df4ddc7ce3c5376331
- name: os_rally
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_rally
version: 6baad96a484172794ffe7c7c637cd3562bcc061a
- name: os_sahara
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_sahara
version: ff06e20db8810215ef0e16327c8f8672a64e8aba
- name: os_swift
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_swift
version: ec76b8e2b4e90d889704073a038665bb44fdbc8d
- name: os_tacker
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_tacker
version: 7f990f3f4be4e150bb9447afbab96eeac88ed05c
- name: os_tempest
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_tempest
version: 5cfbdc3def0473ab3560a68cd4f0ffb8cca7a4e6
- name: os_trove
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-os_trove
version: e74e708fb4cce962b2bded6e1882a0f882a19ef0
- name: plugins
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-plugins
version: 335e9413b07760240a2d7ed9961e4754482cb60c
- name: rabbitmq_server
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-rabbitmq_server
version: ce90c91857de4a840e5db655a3a42b5de0482ede
- name: repo_build
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-repo_build
version: 64577cd93a5e5e2c37be61e07fa4f39a7a87c2ca
- name: repo_server
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-repo_server
version: 1bc95198290e8d563e9ca6137e40b5d15edcce25
- name: rsyslog_client
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-rsyslog_client
version: 88bcc41d9d122ba9ad1b1a428b3238b1b27ecb1f
- name: rsyslog_server
scm: git
src: https://git.openstack.org/openstack/openstack-ansible-rsyslog_server
version: 45cf265fca25a5a5ae6435d8aa91aabcb160ce7b
- name: sshd
scm: git
src: https://github.com/willshersystems/ansible-sshd
version: 537b9b2bc2fd7f23301222098344727f8161993c
- name: bird
scm: git
src: https://github.com/logan2211/ansible-bird
version: 21d7d8de5af9e73c0853d3434a4b3d3f8dd39a70
- name: etcd
scm: git
src: https://github.com/logan2211/ansible-etcd
version: '1.3'
- name: unbound
scm: git
src: https://github.com/logan2211/ansible-unbound
version: '1.6'
- name: resolvconf
scm: git
src: https://github.com/logan2211/ansible-resolvconf
version: '1.4'
- name: ceph-ansible
scm: git
src: https://github.com/ceph/ceph-ansible
version: 0be60456ce98d11ca6acf73d7f7a76c4f9dc5309
- name: opendaylight
scm: git
src: https://github.com/opendaylight/integration-packaging-ansible-opendaylight
version: 4aabce0605ef0f51eef4d6564cc7d779630706c5
- name: haproxy_endpoints
scm: git
src: https://github.com/logan2211/ansible-haproxy-endpoints
version: 49901861b16b8afaa9bccdbc649ac956610ff22b

View File

@@ -0,0 +1,16 @@
# This file should only be used to set python package pins that are
# not present in OpenStack's upper-constraints. Any pins present in
# this file will override any requirements set in *requirements.txt,
# upper-constraints and any roles/vars.
#
# Use this file with caution!
#
###
### These are pinned to ensure exactly the same behaviour forever! ###
### These pins are updated through the sources-branch-updater script ###
###
# Bumping pip to version 10 fails in tempest when trying to install
# packages with an empty list.
pip==19.2
setuptools==40.0.0
wheel==0.31.1

View File

@@ -0,0 +1,38 @@
---
# Copyright 2016, Rackspace US, Inc.
#
# 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.
## NOTICE on items in this file:
## * If you use anything in the *._git_install_branch field that is not a TAG
## make sure to leave an in-line comment as to "why".
## For the sake of anyone else editing this file:
## * If you add services to this file please do so in alphabetical order.
## * Every entry should be name spaced with the name of the client followed by an "_"
## * All items with this file should be separated by `name_` note that the name of the
## package should be one long name with no additional `_` separating it.
### Before this is shipped all of these services should have a tag set as the branch,
### or have a comment / reason attached to them as to why a tag can not work.
## Gnocchi service
## This service has a different stable branch strategy to the rest of OpenStack.
## The SHA is recorded here to make the SHA updating easier.
gnocchi_git_repo: https://github.com/gnocchixyz/gnocchi
gnocchi_git_install_branch: 711e51f706dcc5bc97ad14ddc8108e501befee23 # HEAD of "stable/4.3" as of 17.08.2018
gnocchi_git_project_group: gnocchi_all
gnocchi_git_track_branch: "stable/4.3"

View File

@@ -0,0 +1,294 @@
---
# Copyright 2014, Rackspace US, Inc.
#
# 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.
## NOTICE on items in this file:
## * If you use anything in the *._git_install_branch field that is not a TAG
## make sure to leave an in-line comment as to "why".
## For the sake of anyone else editing this file:
## * If you add services to this file please do so in alphabetical order.
## * Every entry should be name spaced with the name of the client followed by an "_"
## * All items with this file should be separated by `name_` note that the name of the
## package should be one long name with no additional `_` separating it.
### Before this is shipped all of these services should have a tag set as the branch,
### or have a comment / reason attached to them as to why a tag can not work.
## Global Requirements
requirements_git_repo: https://git.openstack.org/openstack/requirements
requirements_git_install_branch: 4425ce22fda513fb7a20e77f28685004296731d0 # HEAD of "master" as of 08.08.2018
requirements_git_track_branch: master
## Aodh service
aodh_git_repo: https://git.openstack.org/openstack/aodh
aodh_git_install_branch: d7dc751a7922fc0a5ea08ec80e3acb2db4b6979e # HEAD of "master" as of 08.08.2018
aodh_git_project_group: aodh_all
aodh_git_track_branch: master
## Barbican service
barbican_git_repo: https://git.openstack.org/openstack/barbican
barbican_git_install_branch: 08ca2287dd845011d940a722f6418c3b73c6c7ae # HEAD of "master" as of 08.08.2018
barbican_git_project_group: barbican_all
barbican_git_track_branch: master
## Ceilometer service
ceilometer_git_repo: https://git.openstack.org/openstack/ceilometer
ceilometer_git_install_branch: 413f9a3261c2b247395c36eef938b53ff8279214 # HEAD of "master" as of 08.08.2018
ceilometer_git_project_group: ceilometer_all
ceilometer_git_track_branch: master
## Cinder service
cinder_git_repo: https://git.openstack.org/openstack/cinder
cinder_git_install_branch: a27d0eb32afc32d745de6a3aafb905ea6151813c # HEAD of "master" as of 08.08.2018
cinder_git_project_group: cinder_all
cinder_git_track_branch: master
## Designate service
designate_git_repo: https://git.openstack.org/openstack/designate
designate_git_install_branch: 6daedf125c6126bd1c32a377fded9d7b46a2b4e9 # HEAD of "master" as of 08.08.2018
designate_git_project_group: designate_all
designate_git_track_branch: master
## Horizon Designate dashboard plugin
designate_dashboard_git_repo: https://git.openstack.org/openstack/designate-dashboard
designate_dashboard_git_install_branch: e41d74a03d46d678c3e86bf98703bcc16dff71f6 # HEAD of "master" as of 08.08.2018
designate_dashboard_git_project_group: horizon_all
designate_dashboard_git_track_branch: master
## Dragonflow service
dragonflow_git_repo: https://git.openstack.org/openstack/dragonflow
dragonflow_git_install_branch: 0f05fc13d7bd26097d16c634c5ddeb63f9bfaecd # HEAD of "master" as of 08.08.2018
dragonflow_git_project_group: neutron_all
dragonflow_git_track_branch: master
## Glance service
glance_git_repo: https://git.openstack.org/openstack/glance
glance_git_install_branch: bfa25c5e5c05399506404e66d53b0d61eaa06ab7 # HEAD of "master" as of 08.08.2018
glance_git_project_group: glance_all
glance_git_track_branch: master
## Heat service
heat_git_repo: https://git.openstack.org/openstack/heat
heat_git_install_branch: 8ca06cfeafc94e739947cf89affa4db57b6bf3c9 # HEAD of "master" as of 08.08.2018
heat_git_project_group: heat_all
heat_git_track_branch: master
## Horizon Heat dashboard plugin
heat_dashboard_git_repo: https://git.openstack.org/openstack/heat-dashboard
heat_dashboard_git_install_branch: df563384901294ac118c45a1e92734f67b6593d8 # HEAD of "master" as of 08.08.2018
heat_dashboard_git_project_group: horizon_all
heat_dashboard_git_track_branch: master
## Horizon service
horizon_git_repo: https://git.openstack.org/openstack/horizon
horizon_git_install_branch: a4443f4be7a7e38ce052080ed157337bc778c18d # HEAD of "master" as of 08.08.2018
horizon_git_project_group: horizon_all
horizon_git_track_branch: master
## Horizon Ironic dashboard plugin
ironic_dashboard_git_repo: https://git.openstack.org/openstack/ironic-ui
ironic_dashboard_git_install_branch: 36840aaa0da8053d2e4032c060a6a45af224572b # HEAD of "master" as of 08.08.2018
ironic_dashboard_git_project_group: horizon_all
ironic_dashboard_git_track_branch: master
## Horizon Magnum dashboard plugin
magnum_dashboard_git_repo: https://git.openstack.org/openstack/magnum-ui
magnum_dashboard_git_install_branch: dcf62a6e80fd3733b530cb76218b2ec5c3532cb6 # HEAD of "master" as of 08.08.2018
magnum_dashboard_git_project_group: horizon_all
magnum_dashboard_git_track_branch: master
## Horizon LBaaS dashboard plugin
neutron_lbaas_dashboard_git_repo: https://git.openstack.org/openstack/neutron-lbaas-dashboard
neutron_lbaas_dashboard_git_install_branch: dde6dfb2eba8eb2f1d9cd61986032b512330b281 # HEAD of "master" as of 08.08.2018
neutron_lbaas_dashboard_git_project_group: horizon_all
neutron_lbaas_dashboard_git_track_branch: master
## Horizon FWaaS dashboard plugin
neutron_fwaas_dashboard_git_repo: https://git.openstack.org//openstack/neutron-fwaas-dashboard
neutron_fwaas_dashboard_git_install_branch: 5ece747e15896cf998e3787aa07f547fa39e3e44 # HEAD of "master" as of 08.08.2018
neutron_fwaas_dashboard_git_project_group: horizon_all
neutron_fwaas_dashboard_git_track_branch: master
## Horizon Sahara dashboard plugin
sahara_dashboard_git_repo: https://git.openstack.org/openstack/sahara-dashboard
sahara_dashboard_git_install_branch: 4585a9d004427f52e34f0cd89374e8ba1cba2dff # HEAD of "master" as of 08.08.2018
sahara_dashboard_git_project_group: horizon_all
sahara_dashboard_git_track_branch: master
## Keystone service
keystone_git_repo: https://git.openstack.org/openstack/keystone
keystone_git_install_branch: a2b510c17638d31d2983317a4261f9dc27507d24 # HEAD of "master" as of 08.08.2018
keystone_git_project_group: keystone_all
keystone_git_track_branch: master
## Neutron service
neutron_git_repo: https://git.openstack.org/openstack/neutron
neutron_git_install_branch: 06f1aa6629d3e54c04ab06ca2808479f5ed9f186 # HEAD of "master" as of 08.08.2018
neutron_git_project_group: neutron_all
neutron_git_track_branch: master
neutron_lbaas_git_repo: https://git.openstack.org/openstack/neutron-lbaas
neutron_lbaas_git_install_branch: e4a9d3c1dfb06482f90699e60b98a94481af5f75 # HEAD of "master" as of 08.08.2018
neutron_lbaas_git_project_group: neutron_all
neutron_lbaas_git_track_branch: master
neutron_vpnaas_git_repo: https://git.openstack.org/openstack/neutron-vpnaas
neutron_vpnaas_git_install_branch: da4fff7e7aa756cd8280e8dd14fb8cccc5777277 # HEAD of "master" as of 08.08.2018
neutron_vpnaas_git_project_group: neutron_all
neutron_vpnaas_git_track_branch: master
neutron_fwaas_git_repo: https://git.openstack.org/openstack/neutron-fwaas
neutron_fwaas_git_install_branch: d61bd2961c5117f22d227a910b7a20e65322bb82 # HEAD of "master" as of 08.08.2018
neutron_fwaas_git_project_group: neutron_all
neutron_fwaas_git_track_branch: master
neutron_dynamic_routing_git_repo: https://git.openstack.org/openstack/neutron-dynamic-routing
neutron_dynamic_routing_git_install_branch: ac63f126c6bd0ab12d6cd80077023c3e5c264e98 # HEAD of "master" as of 08.08.2018
neutron_dynamic_routing_git_project_group: neutron_all
neutron_dynamic_routing_git_track_branch: master
networking_calico_git_repo: https://git.openstack.org/openstack/networking-calico
networking_calico_git_install_branch: 5d852f653552f2332dce48aa425ee842b5b684ad # HEAD of "master" as of 08.08.2018
networking_calico_git_project_group: neutron_all
networking_calico_git_track_branch: master
# ODL is frozen until further notice due to
# https://github.com/openstack/networking-odl/commit/391c1d89ef2b8133d3aafbe7612c7908be106e73#diff-b4ef698db8ca845e5845c4618278f29a
networking_odl_git_repo: https://git.openstack.org/openstack/networking-odl
networking_odl_git_install_branch: 53ff740b2a78626d5b077278997bdcec6b1b0892 # FROZEN HEAD of "master" as of 31.03.2018
networking_odl_git_project_group: neutron_all
networking_odl_git_track_branch: None
# BGPVPN is frozen until further notice due to
# https://github.com/openstack/networking-bgpvpn/commit/e9a0ea199b47f76f69545e04bdb4db44869c388b#diff-b4ef698db8ca845e5845c4618278f29a
networking_bgpvpn_git_repo: https://git.openstack.org/openstack/networking-bgpvpn
networking_bgpvpn_git_install_branch: 3b93ddacd390d92fb144e5660324d4da064ad9a4 # FROZEN HEAD of "master" as of 31.03.2018
networking_bgpvpn_git_project_group: neutron_all
networking_bgpvpn_git_track_branch: None
networking_sfc_git_repo: https://git.openstack.org/openstack/networking-sfc
networking_sfc_git_install_branch: 4c38303620c8a3f38d7261a64ce8532979bf7560 # HEAD of "master" as of 08.08.2018
networking_sfc_git_project_group: neutron_all
networking_sfc_git_track_branch: master
## Nova service
nova_git_repo: https://git.openstack.org/openstack/nova
nova_git_install_branch: c52c2caf97a90de8770e9296d553e0e4a65ac946 # HEAD of "master" as of 08.08.2018
nova_git_project_group: nova_all
nova_git_track_branch: master
## PowerVM Virt Driver
nova_powervm_git_repo: https://git.openstack.org/openstack/nova-powervm
nova_powervm_git_install_branch: 9b518d8c9986249a06e3f5dc1450b66283af91f1 # HEAD of "master" as of 08.08.2018
nova_powervm_git_project_group: nova_all
nova_powervm_git_track_branch: master
## LXD Virt Driver
nova_lxd_git_repo: https://git.openstack.org/openstack/nova-lxd
nova_lxd_git_install_branch: bc8d540c95b3209321658000fd74b0e5065a7ee2 # HEAD of "master" as of 08.08.2018
nova_lxd_git_project_group: nova_all
nova_lxd_git_track_branch: master
## Sahara service
sahara_git_repo: https://git.openstack.org/openstack/sahara
sahara_git_install_branch: 2c6232c9ad37079020ac72a29a54ab794cc80500 # HEAD of "master" as of 08.08.2018
sahara_git_project_group: sahara_all
sahara_git_track_branch: master
## Swift service
swift_git_repo: https://git.openstack.org/openstack/swift
swift_git_install_branch: 7f7482c096d6c587c64a75e207842ab4dee6e8dd # HEAD of "master" as of 08.08.2018
swift_git_project_group: swift_all
swift_git_track_branch: master
## Swift3 middleware
swift_swift3_git_repo: https://git.openstack.org/openstack/swift3
swift_swift3_git_install_branch: 90db5d1510b2a770387961e7bf0fbeae8101ba45 # HEAD of "master" as of 08.08.2018
swift_swift3_git_project_group: swift_all
swift_swift3_git_track_branch: master
## Ironic service
ironic_git_repo: https://git.openstack.org/openstack/ironic
ironic_git_install_branch: 89f68e70e06e24b100d93e751e2a3e8cb8dd9b61 # HEAD of "master" as of 08.08.2018
ironic_git_project_group: ironic_all
ironic_git_track_branch: master
## Magnum service
magnum_git_repo: https://git.openstack.org/openstack/magnum
magnum_git_install_branch: 97b34e67508a69d800239087d0131c6ea128e790 # HEAD of "master" as of 08.08.2018
magnum_git_project_group: magnum_all
magnum_git_track_branch: master
## Trove service
trove_git_repo: https://git.openstack.org/openstack/trove
trove_git_install_branch: 5f2462f0ea4ec2d084db102dbad35bf97eca1135 # HEAD of "master" as of 08.08.2018
trove_git_project_group: trove_all
trove_git_track_branch: master
## Horizon Trove dashboard plugin
trove_dashboard_git_repo: https://git.openstack.org/openstack/trove-dashboard
trove_dashboard_git_install_branch: 9b7f3d9561ce47f370642a3d169fce6469203148 # HEAD of "master" as of 08.08.2018
trove_dashboard_git_project_group: horizon_all
trove_dashboard_git_track_branch: master
## Octavia service
octavia_git_repo: https://git.openstack.org/openstack/octavia
octavia_git_install_branch: a166c89b643c1bdaf3f36004fede25eb7a1c26f5 # HEAD of "master" as of 08.08.2018
octavia_git_project_group: octavia_all
octavia_git_track_branch: master
## Tacker service
tacker_git_repo: https://git.openstack.org/openstack/tacker
tacker_git_install_branch: 5987ad8c56a61e3a6d8fcf37a2557926c585de41 # HEAD of "master" as of 08.08.2018
tacker_git_project_group: tacker_all
tacker_git_track_branch: master
## Congress service
congress_git_repo: https://git.openstack.org/openstack/congress
congress_git_install_branch: 502f40a7d24dd2603bc9e026edc685a956a52e15 # HEAD of "master" as of 08.08.2018
congress_git_project_group: congress_all
congress_git_track_branch: master
## Horizon Octavia dashboard plugin
octavia_dashboard_git_repo: https://git.openstack.org/openstack/octavia-dashboard
octavia_dashboard_git_install_branch: 4f7a5591ae8dd61b25af7f746f20d8f058aa991c # HEAD of "master" as of 08.08.2018
octavia_dashboard_git_project_group: horizon_all
octavia_dashboard_git_track_branch: master

116
tests/test_releases.py Normal file
View File

@@ -0,0 +1,116 @@
import io
import unittest
from unittest.mock import patch
from osa_toolkit import releasing
from prettytable import PrettyTable
from ruamel.yaml import YAML
from packaging import requirements
class TestReleasing(unittest.TestCase):
"""
Test suite for the 'releasing' module
"""
def test_parse_requirements(self):
"""
Tests the `parse_requirements` function.
"""
req = list(releasing.parse_requirements("pip==18.0"))[0]
self.assertEqual(req.name, "pip")
self.assertEqual(req.specifier, requirements.SpecifierSet("==18.0"))
self.assertEqual(req.extras, set())
def test_discover_requirements_sha(self):
"""
Tests the `discover_requirements_sha` function.
"""
expected_sha = "4425ce22fda513fb7a20e77f28685004296731d0"
actual_sha = releasing.discover_requirements_sha(
path="tests/fixtures/repo_packages/openstack_services.yml"
)
self.assertEqual(actual_sha, expected_sha)
def test_print_requirements_state_not_in_uc(self):
"""
Tests `print_requirements_state` when a package is not in the
upper constraints. This test uses a context manager to capture
stdout, which is the equivalent of the `capsys` pytest fixture.
"""
pins = {"pip": "==18.0"}
latest_versions = {"pip": "18.0"}
constraints_versions = {}
# Capture the output of the function
with patch('sys.stdout', new=io.StringIO()) as fake_stdout:
releasing.print_requirements_state(pins, latest_versions, constraints_versions)
captured_output = fake_stdout.getvalue()
# Generate the expected output string for comparison
reftable = PrettyTable(
["Package", "Current Version Spec", "Latest version on PyPI", "Constrained to"]
)
reftable.add_row(["pip", "==18.0", "18.0", "None"])
expected_output = str(reftable) + "\n" # PrettyTable adds a newline
self.assertEqual(captured_output, expected_output)
def test_print_requirements_state_in_uc(self):
"""
Tests `print_requirements_state` when a package is in the
upper constraints.
"""
pins = {"pip": "==18.0"}
latest_versions = {"pip": "18.0"}
constraints_versions = {"pip": "==30.3.0"}
with patch('sys.stdout', new=io.StringIO()) as fake_stdout:
releasing.print_requirements_state(pins, latest_versions, constraints_versions)
captured_output = fake_stdout.getvalue()
reftable = PrettyTable(
["Package", "Current Version Spec", "Latest version on PyPI", "Constrained to"]
)
reftable.add_row(["pip", "==18.0", "18.0", "==30.3.0"])
expected_output = str(reftable) + "\n"
self.assertEqual(captured_output, expected_output)
def test_find_yaml_files(self):
"""
Tests the `find_yaml_files` function.
"""
self.assertEqual(len(releasing.find_yaml_files(["tests/fixtures/repo_packages/*.yaml"])), 0)
self.assertEqual(len(releasing.find_yaml_files(["tests/fixtures/notexistingfolder/"])), 0)
self.assertEqual(
len(releasing.find_yaml_files([
"tests/fixtures/notexistingfolder/",
"tests/fixtures/repo_packages/*"
])), 2
)
self.assertEqual(len(releasing.find_yaml_files(["tests/fixtures/repo_packages/*"])), 2)
def test_build_repos_dict(self):
"""
Tests the `build_repos_dict` function.
"""
yaml = YAML()
with open("tests/fixtures/repo_packages/gnocchi.yml", "r") as fd:
repofiledata = yaml.load(fd)
repos = releasing.build_repos_dict(repofiledata)
self.assertEqual(repos["gnocchi"]["url"], "https://github.com/gnocchixyz/gnocchi")
self.assertEqual(repos["gnocchi"]["sha"], "711e51f706dcc5bc97ad14ddc8108e501befee23")
self.assertEqual(repos["gnocchi"]["trackbranch"], "stable/4.3")
def test_get_sha_from_ref(self):
"""
Tests the `get_sha_from_ref` function.
"""
sha = releasing.get_sha_from_ref(
"https://github.com/openstack/openstack-ansible.git", "newton-eol"
)
self.assertEqual(sha, "bf565c6ae34bb4343b4d6b486bd9b514de370b0a")
if __name__ == '__main__':
unittest.main()

View File

@@ -130,6 +130,7 @@ commands =
coverage run -a {toxinidir}/tests/test_dictutils.py
coverage run -a {toxinidir}/tests/test_ip.py
coverage run -a {toxinidir}/tests/test_filesystem.py
coverage run -a {toxinidir}/tests/test_releases.py
coverage report --show-missing --include={toxinidir}/inventory/*,{toxinidir}/osa_toolkit/*
[testenv:py3-inventory]