Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

This is a containerized interactive script to simplify the quipucords-to-Discovery downstream build process. This means you don't need to install `rhpkg` and `brewkoji` on your own machine or run a custom VM with them any longer!

This script can trigger container builds for quipucords (Discovery) or RPMs for qpc (discovery-cli).
This script can trigger container builds for quipucords (Discovery) or RPMs for qpc (discovery-cli) or quipucordsctl (discoveryctl).

## How do I use it?

Expand All @@ -24,7 +24,7 @@ vi .env
Build the container image:

```sh
podman build -t downstream-builder:latest .
podman build -f Containerfile -t downstream-builder:latest .
```

Connect to the Red Hat VPN. This program communicates with several internal hosts and will fail without appropriate network access.
Expand Down
3 changes: 2 additions & 1 deletion discobuilder/builder/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from discobuilder.adapter.kerberos import kinit
from discobuilder.builder.cli import build_cli # noqa: F401
from discobuilder.builder.installer import build_installer # noqa: F401
from discobuilder.builder.ctl import build_ctl # noqa: F401


def build():
Expand All @@ -13,7 +14,7 @@ def build():
while True:
choice = Prompt.ask(
"What do you want to build?",
choices=["cli", "installer"],
choices=["cli", "installer", "ctl"],
default="cli",
)
eval(f"build_{choice}()")
Expand Down
187 changes: 187 additions & 0 deletions discobuilder/builder/ctl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# TODO: Refactor/deduplicate a lot of similar code between this and ./cli.py.
from textwrap import dedent

import re
from pathlib import Path

import requests
from rich.prompt import Confirm, Prompt

from discobuilder import config, console, warning
from discobuilder.adapter import git
from discobuilder.adapter import rhpkg, rpmbuild


def update_specfile_from_upstream(specfile_path: Path):
quipucords_committish = Prompt.ask(
"Pull from what quipucordsctl committish?", default="main"
)
url = config.QUIPUCORDS_CTL_SPEC_URL.format(quipucords_committish)
response = requests.get(url)
if response.status_code != 200:
raise Exception(f"Unexpected status {response.status_code} downloading {url}")
with specfile_path.open("w") as f:
f.writelines(response.text)


def update_specfile_globals(spec_globals: list[str], specfile_path: Path):
"""
Prompt for changes to %global values and update the spec file accordingly.

This is a destructive operation and will rewrite the spec file contents.
"""
with specfile_path.open("r") as specfile:
specfile_lines = specfile.readlines()

patterns = {
spec_global: rf"^(%global {spec_global} )(\S*)" for spec_global in spec_globals
}
prompts = {
spec_global: f"Enter '{spec_global}' value" for spec_global in spec_globals
}
new_values = {}
dirty = False

for line_number, line in enumerate(specfile_lines):
for spec_global in spec_globals:
if line_match := re.match(patterns[spec_global], line):
old_value = line_match.group(2)
new_value = Prompt.ask(prompts[spec_global], default=old_value)
specfile_lines[line_number] = f"{line_match.group(1)}{new_value}\n"
new_values[spec_global] = new_value
dirty = True
continue # only one match should be possible per line

if dirty:
with specfile_path.open("w") as specfile:
specfile.writelines(specfile_lines)

return new_values, dirty


def import_source_rpm(version):
srpms_dir = rpmbuild.get_srpms_path()
for srpm in list(srpms_dir.glob(f"discoveryctl-{version}-*.src.rpm")):
rhpkg.srpm_import(config.DISCOVERY_CTL_GIT_REPO_PATH, srpm)
# naively expect exactly one match
return
raise Exception(f"No SRPMs found? ({srpms_dir}/discoveryctl-{version}-*.src.rpm)")


def set_up_repo():
if not git.clone_repo(
config.DISCOVERY_CTL_GIT_URL.format(username=config.KERBEROS_USERNAME),
config.DISCOVERY_CTL_GIT_REPO_PATH,
):
try:
git.checkout_ref(config.DISCOVERY_CTL_GIT_REPO_PATH, "master")
git.pull_repo(config.DISCOVERY_CTL_GIT_REPO_PATH)
except git.GitPullFailure as e:
warning(f"{e}")


def build_ctl():
rpmbuild.purge_rpmbuild_tree()
set_up_repo()

if not Confirm.ask("Want to [b]automate[/b] version updates?", default=True):
show_next_steps_summary(with_scratch=True)
return

base_branch = git.get_existing_release_branch(
config.DISCOVERY_CTL_GIT_REPO_PATH,
config.DISCOVERY_CTL_GIT_REMOTE_RELEASE_BRANCH_PREFIX,
config.DISCOVERY_CTL_GIT_REMOTE_RELEASE_BRANCH_DEFAULT,
)
git.new_private_branch(base_branch, config.DISCOVERY_CTL_GIT_REPO_PATH)
target_name = base_branch.split("/")[-1] # maybe not strictly true but good enough

specfile_path = Path(f"{config.DISCOVERY_CTL_GIT_REPO_PATH}/discoveryctl.spec")

if refreshed := Confirm.ask(
"Refresh the spec file from [b]upstream[/b]?", default=True
):
update_specfile_from_upstream(specfile_path)

spec_globals = [
"product_name_lower",
"product_name_title",
"version_ctl",
"server_image",
"ui_image",
]
new_spec_globals, updated = update_specfile_globals(spec_globals, specfile_path)

if refreshed or updated:
new_version = new_spec_globals["version_ctl"]
git.add(config.DISCOVERY_CTL_GIT_REPO_PATH, specfile_path)
git.commit(
config.DISCOVERY_CTL_GIT_REPO_PATH,
default_commit_message=(f"build: update discoveryctl to {new_version}"),
and_push=False,
)
rpmbuild.build_source_rpm(specfile_path)
import_source_rpm(new_version)
git.commit(
config.DISCOVERY_CTL_GIT_REPO_PATH,
default_commit_message="build: update sources",
and_push=False,
)
git.push(config.DISCOVERY_CTL_GIT_REPO_PATH)

if not Confirm.ask("Want to create a [b]scratch[/b] build?", default=True):
show_next_steps_summary(with_scratch=True)
return

release = Prompt.ask("What rhpkg '--release' value?", default="rhel-9")
target = f"{target_name}-candidate"
rhpkg.build(
scratch=True,
release=release,
target=target,
repo_path=config.DISCOVERY_CTL_GIT_REPO_PATH,
)

show_next_steps_summary(with_scratch=False, release=release, target=target)


def show_next_steps_summary(with_scratch=True, release="rhel-9", target=None):
if not target:
target = f"discovery-2-{release}-candidate"

release_message = dedent(
f"""
[b]discoveryctl[/b] should exist at:

{config.DISCOVERY_CTL_GIT_REPO_PATH}
"""
)

if with_scratch:
release_message += dedent(
f"""
Create a scratch build:

cd {config.DISCOVERY_CTL_GIT_REPO_PATH}
rhpkg --release {release} build --target={target} --scratch
"""
)

release_message += dedent(
f"""
Update the release branch and create the release build:

cd {config.DISCOVERY_CTL_GIT_REPO_PATH}
git checkout discovery-2-{release}
git rebase {config.PRIVATE_BRANCH_NAME}
git push
rhpkg build --scratch
rhpkg build

Note that `--release` and `--target` arguments are not required when you invoke `rhpkg build` from the release branches.

Then repeat all of these steps for any other RHEL build releases (`rhel-9`, `rhel-8`).
"""
)
console.rule("Suggested Next Steps")
console.print(dedent(release_message))
22 changes: 22 additions & 0 deletions discobuilder/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,28 @@
DISCOVERY_INSTALLER_GIT_REMOTE_RELEASE_BRANCH_PREFIX = environ.get(
"DISCOVERY_INSTALLER_GIT_REMOTE_RELEASE_BRANCH_PREFIX", "remotes/origin/discovery-"
)
# discoveryctl is downstream repo for packaging quipucordsctl
DISCOVERY_CTL_GIT_URL = environ.get(
"DISCOVERY_CTL_GIT_URL",
"ssh://{username}@pkgs.devel.redhat.com/rpms/discoveryctl.git",
) # see also: https://pkgs.devel.redhat.com/cgit/rpms/discoveryctl
QUIPUCORDS_CTL_SPEC_URL = environ.get(
"DISCOVERY_CTL_UPSTREAM_SPEC_URL",
(
"https://raw.githubusercontent.com/quipucords/quipucordsctl/"
"{0}/quipucordsctl.spec"
),
)
DISCOVERY_CTL_GIT_REPO_PATH = environ.get(
"DISCOVERY_CTL_GIT_REPO_PATH", "/repos/discoveryctl"
)
DISCOVERY_CTL_GIT_REMOTE_RELEASE_BRANCH_DEFAULT = environ.get(
"DISCOVERY_CTL_GIT_REMOTE_RELEASE_BRANCH_DEFAULT",
"remotes/origin/discovery-2-rhel-9",
)
DISCOVERY_CTL_GIT_REMOTE_RELEASE_BRANCH_PREFIX = environ.get(
"DISCOVERY_CTL_GIT_REMOTE_RELEASE_BRANCH_PREFIX", "remotes/origin/discovery-"
)

# how noisy should I be
SHOW_COMMANDS = environ.get("SHOW_COMMANDS", "0") == "1"
Expand Down
Loading