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:
@@ -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.
|
||||
|
||||
|
4449
inventory/openstack_inventory.json
Normal file
4449
inventory/openstack_inventory.json
Normal file
File diff suppressed because it is too large
Load Diff
657
osa_toolkit/releasing.py
Normal file
657
osa_toolkit/releasing.py
Normal 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()
|
@@ -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]
|
||||
|
@@ -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
|
||||
|
196
tests/fixtures/ansible-role-requirements.yml
vendored
Normal file
196
tests/fixtures/ansible-role-requirements.yml
vendored
Normal 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
|
16
tests/fixtures/global-requirements-pins.txt
vendored
Normal file
16
tests/fixtures/global-requirements-pins.txt
vendored
Normal 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
|
38
tests/fixtures/repo_packages/gnocchi.yml
vendored
Normal file
38
tests/fixtures/repo_packages/gnocchi.yml
vendored
Normal 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"
|
294
tests/fixtures/repo_packages/openstack_services.yml
vendored
Normal file
294
tests/fixtures/repo_packages/openstack_services.yml
vendored
Normal 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
116
tests/test_releases.py
Normal 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()
|
1
tox.ini
1
tox.ini
@@ -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]
|
||||
|
Reference in New Issue
Block a user