|
| 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)) |
0 commit comments