Skip to content

Commit 9dfa0cb

Browse files
committed
feature: Add support for the discoveryctl RPM builds
1 parent 68ade01 commit 9dfa0cb

4 files changed

Lines changed: 213 additions & 3 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
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!
66

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

99
## How do I use it?
1010

@@ -24,7 +24,7 @@ vi .env
2424
Build the container image:
2525

2626
```sh
27-
podman build -t downstream-builder:latest .
27+
podman build -f Containerfile -t downstream-builder:latest .
2828
```
2929

3030
Connect to the Red Hat VPN. This program communicates with several internal hosts and will fail without appropriate network access.

discobuilder/builder/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from discobuilder.adapter.kerberos import kinit
55
from discobuilder.builder.cli import build_cli # noqa: F401
66
from discobuilder.builder.installer import build_installer # noqa: F401
7+
from discobuilder.builder.ctl import build_ctl # noqa: F401
78

89

910
def build():
@@ -13,7 +14,7 @@ def build():
1314
while True:
1415
choice = Prompt.ask(
1516
"What do you want to build?",
16-
choices=["cli", "installer"],
17+
choices=["cli", "installer", "ctl"],
1718
default="cli",
1819
)
1920
eval(f"build_{choice}()")

discobuilder/builder/ctl.py

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# TODO: Refactor/deduplicate a lot of similar code between this and ./cli.py.
2+
from textwrap import dedent
3+
4+
import re
5+
from pathlib import Path
6+
7+
import requests
8+
from rich.prompt import Confirm, Prompt
9+
10+
from discobuilder import config, console, warning
11+
from discobuilder.adapter import git
12+
from discobuilder.adapter import rhpkg, rpmbuild
13+
14+
15+
def update_specfile_from_upstream(specfile_path: Path):
16+
quipucords_committish = Prompt.ask(
17+
"Pull from what quipucordsctl committish?", default="main"
18+
)
19+
url = config.QUIPUCORDS_CTL_SPEC_URL.format(quipucords_committish)
20+
response = requests.get(url)
21+
if response.status_code != 200:
22+
raise Exception(f"Unexpected status {response.status_code} downloading {url}")
23+
with specfile_path.open("w") as f:
24+
f.writelines(response.text)
25+
26+
27+
def update_specfile_globals(spec_globals: list[str], specfile_path: Path):
28+
"""
29+
Prompt for changes to %global values and update the spec file accordingly.
30+
31+
This is a destructive operation and will rewrite the spec file contents.
32+
"""
33+
with specfile_path.open("r") as specfile:
34+
specfile_lines = specfile.readlines()
35+
36+
patterns = {
37+
spec_global: rf"^(%global {spec_global} )(\S*)" for spec_global in spec_globals
38+
}
39+
prompts = {
40+
spec_global: f"Enter '{spec_global}' value" for spec_global in spec_globals
41+
}
42+
new_values = {}
43+
dirty = False
44+
45+
for line_number, line in enumerate(specfile_lines):
46+
for spec_global in spec_globals:
47+
if line_match := re.match(patterns[spec_global], line):
48+
old_value = line_match.group(2)
49+
new_value = Prompt.ask(prompts[spec_global], default=old_value)
50+
specfile_lines[line_number] = f"{line_match.group(1)}{new_value}\n"
51+
new_values[spec_global] = new_value
52+
dirty = True
53+
continue # only one match should be possible per line
54+
55+
if dirty:
56+
with specfile_path.open("w") as specfile:
57+
specfile.writelines(specfile_lines)
58+
59+
return new_values, dirty
60+
61+
62+
def import_source_rpm(version):
63+
srpms_dir = rpmbuild.get_srpms_path()
64+
for srpm in list(srpms_dir.glob(f"discoveryctl-{version}-*.src.rpm")):
65+
rhpkg.srpm_import(config.DISCOVERY_CTL_GIT_REPO_PATH, srpm)
66+
# naively expect exactly one match
67+
return
68+
raise Exception(f"No SRPMs found? ({srpms_dir}/discoveryctl-{version}-*.src.rpm)")
69+
70+
71+
def set_up_repo():
72+
if not git.clone_repo(
73+
config.DISCOVERY_CTL_GIT_URL.format(username=config.KERBEROS_USERNAME),
74+
config.DISCOVERY_CTL_GIT_REPO_PATH,
75+
):
76+
try:
77+
git.checkout_ref(config.DISCOVERY_CTL_GIT_REPO_PATH, "master")
78+
git.pull_repo(config.DISCOVERY_CTL_GIT_REPO_PATH)
79+
except git.GitPullFailure as e:
80+
warning(f"{e}")
81+
82+
83+
def build_ctl():
84+
rpmbuild.purge_rpmbuild_tree()
85+
set_up_repo()
86+
87+
if not Confirm.ask("Want to [b]automate[/b] version updates?", default=True):
88+
show_next_steps_summary(with_scratch=True)
89+
return
90+
91+
base_branch = git.get_existing_release_branch(
92+
config.DISCOVERY_CTL_GIT_REPO_PATH,
93+
config.DISCOVERY_CTL_GIT_REMOTE_RELEASE_BRANCH_PREFIX,
94+
config.DISCOVERY_CTL_GIT_REMOTE_RELEASE_BRANCH_DEFAULT,
95+
)
96+
git.new_private_branch(base_branch, config.DISCOVERY_CTL_GIT_REPO_PATH)
97+
target_name = base_branch.split("/")[-1] # maybe not strictly true but good enough
98+
99+
specfile_path = Path(f"{config.DISCOVERY_CTL_GIT_REPO_PATH}/discoveryctl.spec")
100+
101+
if refreshed := Confirm.ask(
102+
"Refresh the spec file from [b]upstream[/b]?", default=True
103+
):
104+
update_specfile_from_upstream(specfile_path)
105+
106+
spec_globals = [
107+
"product_name_lower",
108+
"product_name_title",
109+
"version_ctl",
110+
"server_image",
111+
"ui_image",
112+
]
113+
new_spec_globals, updated = update_specfile_globals(spec_globals, specfile_path)
114+
115+
if refreshed or updated:
116+
new_version = new_spec_globals["version_ctl"]
117+
git.add(config.DISCOVERY_CTL_GIT_REPO_PATH, specfile_path)
118+
git.commit(
119+
config.DISCOVERY_CTL_GIT_REPO_PATH,
120+
default_commit_message=(f"build: update discoveryctl to {new_version}"),
121+
and_push=False,
122+
)
123+
rpmbuild.build_source_rpm(specfile_path)
124+
import_source_rpm(new_version)
125+
git.commit(
126+
config.DISCOVERY_CTL_GIT_REPO_PATH,
127+
default_commit_message="build: update sources",
128+
and_push=False,
129+
)
130+
git.push(config.DISCOVERY_CTL_GIT_REPO_PATH)
131+
132+
if not Confirm.ask("Want to create a [b]scratch[/b] build?", default=True):
133+
show_next_steps_summary(with_scratch=True)
134+
return
135+
136+
release = Prompt.ask("What rhpkg '--release' value?", default="rhel-9")
137+
target = f"{target_name}-candidate"
138+
rhpkg.build(
139+
scratch=True,
140+
release=release,
141+
target=target,
142+
repo_path=config.DISCOVERY_CTL_GIT_REPO_PATH,
143+
)
144+
145+
show_next_steps_summary(with_scratch=False, release=release, target=target)
146+
147+
148+
def show_next_steps_summary(with_scratch=True, release="rhel-9", target=None):
149+
if not target:
150+
target = f"discovery-2-{release}-candidate"
151+
152+
release_message = dedent(
153+
f"""
154+
[b]discoveryctl[/b] should exist at:
155+
156+
{config.DISCOVERY_CTL_GIT_REPO_PATH}
157+
"""
158+
)
159+
160+
if with_scratch:
161+
release_message += dedent(
162+
f"""
163+
Create a scratch build:
164+
165+
cd {config.DISCOVERY_CTL_GIT_REPO_PATH}
166+
rhpkg --release {release} build --target={target} --scratch
167+
"""
168+
)
169+
170+
release_message += dedent(
171+
f"""
172+
Update the release branch and create the release build:
173+
174+
cd {config.DISCOVERY_CTL_GIT_REPO_PATH}
175+
git checkout discovery-2-{release}
176+
git rebase {config.PRIVATE_BRANCH_NAME}
177+
git push
178+
rhpkg build --scratch
179+
rhpkg build
180+
181+
Note that `--release` and `--target` arguments are not required when you invoke `rhpkg build` from the release branches.
182+
183+
Then repeat all of these steps for any other RHEL build releases (`rhel-9`, `rhel-8`).
184+
"""
185+
)
186+
console.rule("Suggested Next Steps")
187+
console.print(dedent(release_message))

discobuilder/config.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,28 @@
5252
DISCOVERY_INSTALLER_GIT_REMOTE_RELEASE_BRANCH_PREFIX = environ.get(
5353
"DISCOVERY_INSTALLER_GIT_REMOTE_RELEASE_BRANCH_PREFIX", "remotes/origin/discovery-"
5454
)
55+
# discoveryctl is downstream repo for packaging quipucordsctl
56+
DISCOVERY_CTL_GIT_URL = environ.get(
57+
"DISCOVERY_CTL_GIT_URL",
58+
"ssh://{username}@pkgs.devel.redhat.com/rpms/discoveryctl.git",
59+
) # see also: https://pkgs.devel.redhat.com/cgit/rpms/discoveryctl
60+
QUIPUCORDS_CTL_SPEC_URL = environ.get(
61+
"DISCOVERY_CTL_UPSTREAM_SPEC_URL",
62+
(
63+
"https://raw.githubusercontent.com/quipucords/quipucordsctl/"
64+
"{0}/quipucordsctl.spec"
65+
),
66+
)
67+
DISCOVERY_CTL_GIT_REPO_PATH = environ.get(
68+
"DISCOVERY_CTL_GIT_REPO_PATH", "/repos/discoveryctl"
69+
)
70+
DISCOVERY_CTL_GIT_REMOTE_RELEASE_BRANCH_DEFAULT = environ.get(
71+
"DISCOVERY_CTL_GIT_REMOTE_RELEASE_BRANCH_DEFAULT",
72+
"remotes/origin/discovery-2-rhel-9",
73+
)
74+
DISCOVERY_CTL_GIT_REMOTE_RELEASE_BRANCH_PREFIX = environ.get(
75+
"DISCOVERY_CTL_GIT_REMOTE_RELEASE_BRANCH_PREFIX", "remotes/origin/discovery-"
76+
)
5577

5678
# how noisy should I be
5779
SHOW_COMMANDS = environ.get("SHOW_COMMANDS", "0") == "1"

0 commit comments

Comments
 (0)