contrib: add new fix-versions mode to apiage.py

Fixes: #718

This change adds a new "fix-versions" mode to apiage.py, as well as the
ability to set placeholder version values when adding a new API. The
fix-versions mode replaces placeholder versions with real version
numbers. When fixing versions, the --fix-filter-pkg & --fix-filter-func
options can be used to narrow down what APIs will be fixed in case not
all version placeholder should be fixed to the same values.

Note that the placeholders being with a '$' character and look a bit
like a shell variable. However, the text is simply a reminder - only the
'$' prefix is significant. This indicates that the field is a
placeholder.

Signed-off-by: John Mulligan <jmulligan@redhat.com>
This commit is contained in:
John Mulligan 2022-08-01 14:18:11 -04:00 committed by mergify[bot]
parent aa0240aa56
commit d6bf51115d
1 changed files with 81 additions and 1 deletions

View File

@ -9,6 +9,7 @@ PDX-License-Identifier: MIT
import argparse import argparse
import copy import copy
import json import json
import re
import sys import sys
@ -131,6 +132,24 @@ def api_compare(tracked, src):
return problems return problems
def api_fix_versions(tracked, values, pred=None):
"""Walks through tracked API and fixes any placeholder versions to real version numbers.
"""
for pkg, pkg_api in tracked.items():
for api in pkg_api.get("deprecated_api", []):
if pred and not pred(pkg, api["name"]):
print(f"Skipping {pkg}:{api['name']} due to filter")
continue
_vfix(pkg, "deprecated_in_version", api, values)
_vfix(pkg, "expected_remove_version", api, values)
for api in pkg_api.get("preview_api", []):
if pred and not pred(pkg, api["name"]):
print(f"Skipping {pkg}:{api['name']} due to filter")
continue
_vfix(pkg, "added_in_version", api, values)
_vfix(pkg, "expected_stable_version", api, values)
def format_markdown(tracked, outfh): def format_markdown(tracked, outfh):
print("<!-- GENERATED FILE: DO NOT EDIT DIRECTLY -->", file=outfh) print("<!-- GENERATED FILE: DO NOT EDIT DIRECTLY -->", file=outfh)
print("", file=outfh) print("", file=outfh)
@ -192,6 +211,33 @@ def _vfmt(x, y, z):
return f"v{x}.{y}.{z}" return f"v{x}.{y}.{z}"
def _vfix(pkg, key, api, values):
if api.get(key, "").startswith("$"):
try:
val = values[key]
except KeyError:
raise ValueError(f"missing {key} in values: {key} must be provided to fix apis")
api[key] = val
print(f"Updated {pkg}:{api['name']} {key}={values[key]}")
def _make_fix_filter(cli):
pkgre = namere = None
if cli.fix_filter_pkg:
pkgre = re.compile(cli.fix_filter_pkg)
if cli.fix_filter_func:
namere = re.compile(cli.fix_filter_func)
def f(pkg, fname):
if pkgre and not pkgre.match(pkg):
return False
if namere and not namere.match(fname):
return False
return True
return f
def tag_to_versions(cli, version_tag): def tag_to_versions(cli, version_tag):
# first: parse the tag # first: parse the tag
if not version_tag.startswith("v"): if not version_tag.startswith("v"):
@ -214,6 +260,15 @@ def tag_to_versions(cli, version_tag):
cli.deprecated_in_version = _vfmt(x, y + 1, z) cli.deprecated_in_version = _vfmt(x, y + 1, z)
def placeholder_versions(cli):
if not cli.added_in_version:
cli.added_in_version = "$NEXT_RELEASE"
if not cli.stable_in_version:
cli.stable_in_version = "$NEXT_RELEASE_STABLE"
if not cli.deprecated_in_version:
cli.deprecated_in_version = "$NEXT_RELEASE"
def main(): def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument( parser.add_argument(
@ -236,7 +291,7 @@ def main():
) )
parser.add_argument( parser.add_argument(
"--mode", "--mode",
choices=("compare", "update", "write-doc"), choices=("compare", "update", "write-doc", "fix-versions"),
default="compare", default="compare",
help="either update current state or compare current state to source", help="either update current state or compare current state to source",
) )
@ -273,6 +328,19 @@ def main():
" set version values if not otherwise specified." " set version values if not otherwise specified."
), ),
) )
parser.add_argument(
"--placeholder-versions",
action="store_true",
help="Specify special placeholder values for version numbers.",
)
parser.add_argument(
"--fix-filter-pkg",
help="Specify a regular expression to filter on package names.",
)
parser.add_argument(
"--fix-filter-func",
help="Specify a regular expression to filter on function names.",
)
cli = parser.parse_args() cli = parser.parse_args()
api_src = read_json(cli.source) if cli.source else {} api_src = read_json(cli.source) if cli.source else {}
@ -286,6 +354,10 @@ def main():
if cli.current_tag: if cli.current_tag:
tag_to_versions(cli, cli.current_tag) tag_to_versions(cli, cli.current_tag)
elif cli.placeholder_versions:
if cli.mode == "fix-versions":
raise ValueError("fix-versions requires real version numbers")
placeholder_versions(cli)
if cli.mode == "compare": if cli.mode == "compare":
# just compare the json files. useful for CI # just compare the json files. useful for CI
@ -311,6 +383,14 @@ def main():
sys.exit(1) sys.exit(1)
write_json(cli.current, api_tracked) write_json(cli.current, api_tracked)
write_markdown(cli.document, api_tracked) write_markdown(cli.document, api_tracked)
elif cli.mode == "fix-versions":
values = {}
_setif(values, "added_in_version", cli.added_in_version)
_setif(values, "expected_stable_version", cli.stable_in_version)
_setif(values, "deprecated_in_version", cli.deprecated_in_version)
_setif(values, "expected_remove_version", cli.remove_in_version)
api_fix_versions(api_tracked, values=values, pred=_make_fix_filter(cli))
write_json(cli.current, api_tracked)
elif cli.mode == "write-doc": elif cli.mode == "write-doc":
write_markdown(cli.document, api_tracked) write_markdown(cli.document, api_tracked)