Require --rhel-target

This commit is contained in:
Troy Dawson 2023-02-23 10:01:39 -08:00
parent 0271c67c5a
commit 1e7ef8239a
2 changed files with 300 additions and 3 deletions

View file

@ -23,7 +23,11 @@ import centpkg.utils
from pyrpkg.cli import cliClient
from pyrpkg import rpkgError
from six.moves.urllib_parse import urlparse
import six.moves.configparser as ConfigParser
import json
import koji
import os
_DEFAULT_API_BASE_URL = 'https://gitlab.com'
@ -126,6 +130,122 @@ class centpkgClient(cliClient):
msg = "Remote with name '{0}' already exists."
self.log.info(msg.format(remote_name))
# Overloaded build
def register_build(self):
# Do all the work from the super class
super(centpkgClient, self).register_build()
build_parser = self.subparsers.choices['build']
build_parser.formatter_class = argparse.RawDescriptionHelpFormatter
build_parser.description = textwrap.dedent('''
{0}
centpkg now sets the rhel metadata with --rhel-target.
* exception - This will build for the current in-development Y-stream release.
It is equivalent to passing latest when not in the Blocker and Exception Phase.
* zstream - If pre-GA of a y-stream release, this will build for 0day.
If post-GA of a Y-stream release, this will build for the Z-stream of that release.
* latest - This will always build for the next Y-stream release
'''.format('\n'.join(textwrap.wrap(build_parser.description))))
# Now add our additional option
build_parser.add_argument(
'--rhel-target',
choices=['exception', 'zstream', 'latest'],
default='latest',
help='Set the rhel-target metadata')
# Overloaded _build
def _build(self, sets=None):
# Only run if we have internal configuraions, or scratch
internal_config_file = "/etc/rpkg/centpkg_internal.conf"
if os.path.exists(internal_config_file):
# Get our internal only variables
cfg = ConfigParser.SafeConfigParser()
cfg.read(internal_config_file)
pp_api_url = config_get_safely(cfg, "centpkg.internal", 'pp_api_url')
gitbz_query_url = config_get_safely(cfg, "centpkg.internal", 'gitbz_query_url')
rhel_dist_git = config_get_safely(cfg, "centpkg.internal", 'rhel_dist_git')
# Find out divergent branch and stabalization
stream_version = self.cmd.target.split('-')[0]
rhel_version = centpkg.utils.stream_mapping(stream_version)
active_y, in_stabilization = centpkg.utils.determine_active_y_version(rhel_version, pp_api_url)
divergent_branch = centpkg.utils.does_divergent_branch_exist(
self.cmd.repo_name,
rhel_version,
rhel_dist_git,
pp_api_url,
"rpms")
# Good to know
if divergent_branch :
print("divergent_branch: TRUE")
else:
print("divergent_branch: FALSE")
if in_stabilization :
print("in_stabilization: TRUE")
else:
print("in_stabilization: FALSE")
# Update args.custom_user_metadata
if hasattr(self.args, 'custom_user_metadata') and self.args.custom_user_metadata:
try:
temp_custom_user_metadata = json.loads(self.args.custom_user_metadata)
# Use ValueError instead of json.JSONDecodeError for Python 2 and 3 compatibility
except ValueError as e:
self.parser.error("--custom-user-metadata is not valid JSON: %s" % e)
if not isinstance(temp_custom_user_metadata, dict):
self.parser.error("--custom-user-metadata must be a JSON object")
if hasattr(self.args, 'rhel_target') and self.args.rhel_target:
temp_custom_user_metadata["rhel-target"] = self.args.rhel_target
else:
if divergent_branch and not in_stabilization :
temp_custom_user_metadata["rhel-target"] = "latest"
elif not divergent_branch and not in_stabilization :
temp_custom_user_metadata["rhel-target"] = "zstream"
else:
print("We are currently in Stabalization mode")
print("You must either set the rhel-target (--rhel-target)")
print("or branch for the previous version.")
print("Exiting")
raise SystemExit
self.args.custom_user_metadata = json.dumps(temp_custom_user_metadata)
else:
if hasattr(self.args, 'rhel_target') and self.args.rhel_target:
temp_custom_user_metadata = {"rhel-target": self.args.rhel_target}
self.args.custom_user_metadata = json.dumps(temp_custom_user_metadata)
else:
if divergent_branch and not in_stabilization :
self.args.custom_user_metadata = '{"rhel-target": "latest"}'
elif not divergent_branch and not in_stabilization :
self.args.custom_user_metadata = '{"rhel-target": "zstream"}'
else:
print("We are currently in Stabalization mode")
print("You must either set the rhel-target (--rhel-target)")
print("or branch for the previous version.")
print("Exiting")
raise SystemExit
# Good to know, but take out for final cut
print('Metadata: %r', self.args.custom_user_metadata)
# Purposely fail during testing so we do not have so many builds
#self.args.custom_user_metadata = json.loads(self.args.custom_user_metadata)
else:
if not self.args.scratch:
print("NO SCRATCH BUILD")
print("Only scratch builds are allowed without internal configurations")
print("Exiting")
raise SystemExit
# Proceed with build
return super(centpkgClient, self)._build(sets)
def register_request_gated_side_tag(self):
"""Register command line parser for subcommand request-gated-side-tag"""
parser = self.subparsers.add_parser(

View file

@ -10,16 +10,22 @@
# option) any later version. See http://www.gnu.org/copyleft/gpl.html for
# the full text of the license.
import re
import json
import git
import json
import logging
import os
import pytz
import re
import requests
import sys
from datetime import date, datetime
from pyrpkg import rpkgError
from requests.exceptions import ConnectionError
from six.moves.configparser import NoOptionError, NoSectionError
from six.moves.urllib.parse import quote_plus, urlparse
import git as gitpython
dist_git_config = None
def do_fork(logger, base_url, token, repo_name, namespace, cli_name):
@ -255,3 +261,174 @@ def get_repo_name(name, org='rpms'):
repo_name = get_canonical_repo_name(dist_git_config, name)
return '%s/%s' % (org, repo_name)
def stream_mapping(csname):
"""
Given a CentOS Stream name, map it to the corresponding RHEL name.
Parameters
----------
csname: str
The CentOS Stream name.
Returns
-------
str
Correspoinding RHEL name.
"""
if csname == "c8s" or csname == "cs8" :
return "rhel-8"
if csname == "c9s" or csname == "cs9" :
return "rhel-9"
if csname == "c10s" or csname == "cs10" :
return "rhel-10"
if csname == "c11s" or csname == "cs11" :
return "rhel-11"
return None
def does_divergent_branch_exist(repo_name, rhel_version, rhel_dist_git, pp_api_url, namespace):
logger = logging.getLogger(__name__)
# Determine if the Y-1 branch exists for this repo
# Look up the Y-1 branch name
divergent_branch = determine_divergent_branch(
rhel_version,
pp_api_url,
namespace,
)
logger.debug("Divergent branch: {}".format(divergent_branch))
g = gitpython.cmd.Git()
try:
g.ls_remote(
"--exit-code",
os.path.join(rhel_dist_git, namespace, repo_name),
divergent_branch,
)
branch_exists = True
except gitpython.GitCommandError as e:
t, v, tb = sys.exc_info()
# `git ls-remote --exit-code` returns "2" if it cannot find the ref
if e.status == 2:
branch_exists = False
else:
raise
return branch_exists
def determine_divergent_branch(rhel_version, pp_api_url, namespace):
logger = logging.getLogger(__name__)
# Query the "package pages" API for the current active Y-stream release
# Phase 230 is "Planning / Development / Testing" (AKA DeveTestDoc)
request_params = {
"phase": 230,
"product__shortname": "rhel",
"relgroup__shortname": rhel_version,
"format": "json",
}
res = requests.get(
os.path.join(pp_api_url, "latest", "releases"),
params=request_params,
timeout=60,
)
res.raise_for_status()
payload = json.loads(res.text)
logger.debug(
"Response from PP API: {}".format(json.dumps(payload, indent=2))
)
if len(payload) < 1:
raise RuntimeError("Received zero potential release matches)")
active_y_version = -1
for entry in payload:
shortname = entry["shortname"]
# The shortname is in the form rhel-9-1.0
# Extract the active Y-stream version
m = re.search("(?<={}-)\d+(?=\.0)".format(rhel_version), shortname)
if not m:
raise RuntimeError(
"Could not determine active Y-stream version from shortname"
)
y_version = int(m.group(0))
if y_version > active_y_version:
active_y_version = y_version
# The divergent branch is Y-1
return "{}.{}.0".format(rhel_version, active_y_version - 1)
def _datesplit(isodate):
date_string_tuple = isodate.split('-')
return [ int(x) for x in date_string_tuple ]
def determine_active_y_version(rhel_version, pp_api_url):
"""
Returns: A 2-tuple of the active Y-stream version(int) and whether we are
in the Exception Phase(bool)
"""
logger = logging.getLogger(__name__)
# Query the "package pages" API for the current active Y-stream release
# Phase 230 is "Planning / Development / Testing" (AKA DeveTestDoc)
request_params = {
"phase": 230,
"product__shortname": "rhel",
"relgroup__shortname": rhel_version,
"format": "json",
}
res = requests.get(
os.path.join(pp_api_url, "latest", "releases"),
params=request_params,
timeout=60,
)
res.raise_for_status()
payload = json.loads(res.text)
logger.debug(
"Response from PP API: {}".format(json.dumps(payload, indent=2))
)
if len(payload) < 1:
raise RuntimeError("Received zero potential release matches)")
release_id = -1
active_y_version = -1
for entry in payload:
shortname = entry["shortname"]
# The shortname is in the form rhel-9-1.0
# Extract the active Y-stream version
m = re.search("(?<={}-)\d+(?=\.0)".format(rhel_version), shortname)
if not m:
raise RuntimeError(
"Could not determine active Y-stream version from shortname"
)
y_version = int(m.group(0))
if y_version > active_y_version:
active_y_version = y_version
release_id = entry["id"]
# Now look up whether we are in the Exception Phase for this Y-stream release
request_params = {
"name__regex": "Exception Phase",
"format": "json",
}
res = requests.get(os.path.join(pp_api_url, "latest", "releases", str(release_id), "schedule-tasks"), params=request_params)
res.raise_for_status()
payload = json.loads(res.text)
# This lookup *must* return exactly one value or the Product Pages are
# wrong and must be fixed.
assert len(payload) == 1
# Determine if this Y-stream release is in the exception phase
today = datetime.now(tz=pytz.utc).date()
exception_start_date = date(*_datesplit(payload[0]["date_start"]))
in_exception_phase = today >= exception_start_date
logger.debug("Active Y-stream: {}, Enforcing: {}".format(active_y_version, in_exception_phase))
return active_y_version, in_exception_phase