From 1bccef7ff413ad99e80d4bcfb6d41214d11a73d0 Mon Sep 17 00:00:00 2001 From: Antoni Segura Puimedon Date: Sat, 15 Feb 2025 07:35:12 +0100 Subject: [PATCH 1/2] Build containers without python deps This change allows building the container images without the python dependencies that are getting harder to get by. As a part of this change, version2.py is faithfully converted to a shell script of the same name. Co-authored-by: Antoni Segura Puimedon Co-authored-by: Mark Old Assisted-by: Claude Sonnet 4.5 --- Dockerfile | 2 - Makefile | 5 +- hack/ubi-build-deps.sh | 3 +- hack/version2.py | 238 ------------------------------- hack/version2.sh | 317 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 321 insertions(+), 244 deletions(-) delete mode 100755 hack/version2.py create mode 100755 hack/version2.sh diff --git a/Dockerfile b/Dockerfile index cdff3cde349..159100375e3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,6 @@ COPY . . RUN if [ -f "${BUILD_IMAGE_CUSTOMIZATION}" ]; then "${BUILD_IMAGE_CUSTOMIZATION}"; fi RUN if [ -e "/activation-key/org" ]; then dnf install -y subscription-manager && dnf clean all && rm -rf /var/cache/dnf/*; unlink /etc/rhsm-host; subscription-manager register --force --org $(cat "/activation-key/org") --activationkey $(cat "/activation-key/activationkey"); fi -RUN python3 -m ensurepip ENV GO=${GO} RUN make build-hiveutil @@ -29,7 +28,6 @@ RUN if [ -f "${BUILD_IMAGE_CUSTOMIZATION}" ]; then "${BUILD_IMAGE_CUSTOMIZATION} ENV SMDEV_CONTAINER_OFF=${CONTAINER_SUB_MANAGER_OFF} RUN if [ -e "/activation-key/org" ]; then dnf install -y subscription-manager && dnf clean all && rm -rf /var/cache/dnf/*; unlink /etc/rhsm-host; subscription-manager register --force --org $(cat "/activation-key/org") --activationkey $(cat "/activation-key/activationkey"); fi -RUN python3 -m ensurepip ENV GO=${GO} RUN make build-hiveadmission build-manager build-operator && \ make build-hiveutil diff --git a/Makefile b/Makefile index 9d11cbc7cf8..d2943496091 100644 --- a/Makefile +++ b/Makefile @@ -80,8 +80,9 @@ endif # we don't tag versions. Override using the same versioning we apply to OperatorHub builds: # v{major}.{minor}.{commitcount}-{sha} # Note that building against a local commit may result in {major}.{minor} being rendered as -# `UnknownBranch`. However, the {commitcount} and {sha} should still be accurate. -SOURCE_GIT_TAG := $(shell export HOME=$(HOME); python3 -m ensurepip >&2; python3 -mpip --no-cache install --user gitpython pyyaml >&2; hack/version2.py) +# 0.0.x-y if it is an `UnknownBranch`. However, the {commitcount} and {sha} +# should still be accurate. +SOURCE_GIT_TAG := v$(shell hack/version2.sh) BINDATA_INPUTS :=./config/sharded_controllers/... ./config/hiveadmission/... ./config/controllers/... ./config/rbac/... ./config/configmaps/... $(call add-bindata,operator,$(BINDATA_INPUTS),,assets,pkg/operator/assets/bindata.go) diff --git a/hack/ubi-build-deps.sh b/hack/ubi-build-deps.sh index 8bf5bbc01e3..5d75d2b6eb4 100755 --- a/hack/ubi-build-deps.sh +++ b/hack/ubi-build-deps.sh @@ -2,8 +2,7 @@ dnf install -y \ git \ golang \ - make \ - python3 + make # Since go 1.24.x is not available in ubi8, let's go upstream go install golang.org/dl/go1.24.13@latest diff --git a/hack/version2.py b/hack/version2.py deleted file mode 100755 index 832175b999e..00000000000 --- a/hack/version2.py +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/env python3 - -import enum -import os -import re -import sys - -import git - -# Match things like 'mce-2.0' or origin/mce-2.0, capturing: -# 1: 'origin/' -# 2: '2.0' (used for the bundle semver prefix) -MCE_BRANCH_RE = re.compile("^([^/]+/)?mce-(\\d+\\.\\d+)$") - -MASTER_BRANCH_RE = re.compile("^([^/]+/)?master$") - -# MASTER_BRANCH_PREFIX is the prefix of the Hive version that will be constructed by -# this script if we are tracking the master branch. -# The version used for images and bundles will be: -# "v{prefix}.{number of commits}-{git hash}" -# e.g. "v1.2.3187-18827f6" -MASTER_BRANCH_PREFIX = "1.2" - -# UNKNOWN_BRANCH_PREFIX is the fallback if we can't determine an MCE or master branch -UNKNOWN_BRANCH_PREFIX = "0.0" - - -class Version: - def __init__(self, repo_dir: str, branch_name: str = None, commit_ish: str = None): - self.repo = git.Repo(repo_dir) - - if commit_ish: - # Commit explicitly given - self.commit = self.repo.rev_parse(commit_ish) - else: - # Assume HEAD. If we got branch_name but not commit_ish, and they're sitting somewhere unrelated, - # that's a user error. (To build on the branch commit, just specify the branch to commit_ish.) - self.commit = self.repo.head.commit - - self._branch_name = "" - if branch_name: - self._branch_name = self._validate_branch(branch_name) - else: - # Before looking for related refs: - # If we have an active branch, and it's equal to our commit, use it. - try: - if self.repo.active_branch.commit == self.commit: - self._branch_name = self.repo.active_branch.name - log( - f"Using active branch {self._branch_name} since it corresponds to commit {self.shortsha}", - level="debug", - ) - except TypeError: - log("No active branch -- detached HEAD?", level="debug") - - if not self._branch_name: - log( - f"Trying to discover a suitable branch from commit {self.shortsha}...", - level="debug", - ) - self._branch_name = self._branch_from_commit(commit_ish) - - self._prefix = self._prefix_from_branch() - - self._commit_count = self.repo.git.rev_list( - "--count", - "{parent}..{commit_hash}".format( - parent=self.repo.git.rev_list("--max-parents=0", self.commit.hexsha), - commit_hash=self.commit.hexsha, - ), - ) - - def _validate_branch(self, branch_name): - """Ensure the named branch is related to (at, an ancestor of, or descended from) our commit. - - :param branch_name (str): A branch name. As a convenience, if not fully qualified, and no such branch exists - locally, we will try to find it at origin/ and upstream/. - :return branch_name (str): The branch name. - :error: If the named branch is not related to our commit. - """ - branch_commit = self._find_branch(branch_name) - if branch_commit == self.commit: - log("Branch matches commit", level="debug") - return branch_name - if self.repo.is_ancestor(self.commit, branch_commit): - log( - "Commit is an ancestor of branch: you are requesting a version for an old commit!", - level="debug", - ) - return branch_name - if self.repo.is_ancestor(branch_commit, self.commit): - log( - "Branch is an ancestor of commit: you are requesting a version for an unmerged commit!", - level="debug", - ) - return branch_name - # Die - log( - f"Commit {self.shortsha} and branch {branch_name} ({branch_commit.hexsha[0:8]}) do not appear to be related!", - level="fatal", - ) - - def _branch_from_commit(self, commit_ish: str): - here = set() - ancestors = set() - descendants = set() - # Sadly, this is kind of expensive. - for ref in self.repo.references: - # If we got an explicit commit_ish, and it's already a branch name, use it. - # Exact match - if ref.name == commit_ish: - log(f"Found a branch for commit_ish {commit_ish}", level="debug") - return commit_ish - # Match minus remote name - if ref.is_remote() and ref.remote_head == commit_ish: - log( - f"Found a branch for commit_ish {commit_ish} at remote '{ref.remote_name}'", - level="debug", - ) - return commit_ish - - refname = ref.remote_head if ref.is_remote() else ref.name - if refname == "HEAD" or 'konflux/' in refname: - continue - - # Okay, now start using self._commit, which is already rev_parse()d. - # If this ref is at our commit, it's a candidate - if ref.commit == self.commit: - here.add(refname) - elif self.repo.is_ancestor(ref.commit, self.commit): - ancestors.add(refname) - elif self.repo.is_ancestor(self.commit, ref.commit): - descendants.add(refname) - - # First look for a unique branch right here - if len(here) == 1: - branch = list(here)[0] - log( - f"Found unique branch {branch} at commit {self.shortsha}", level="debug" - ) - return branch - if len(here) > 1: - # We can't handle this - log( - f"Found {len(here)} branches at commit {self.shortsha}! Please specify a branch name explicitly.", - level="fatal", - ) - - # Next look for named descendants of our commit. This indicates we're versioning an old commit on the branch. - if len(descendants) == 1: - branch = list(descendants)[0] - log( - f"Found branch {branch} descended from commit {self.shortsha}", - level="debug", - ) - return branch - - log(f"descendants: {descendants}", level="debug") - - if len(descendants) == 0: - log(f"WARNING: Are you versioning an unmerged commit?", level="warning") - - if len(ancestors) == 1: - branch = list(ancestors)[0] - log( - f"Found branch {branch} which is an ancestor of commit {self.shortsha}", - level="debug", - ) - return branch - - log( - f"Could not determine a branch! Please specify one explicitly.", - level="fatal", - ) - - @property - def shortsha(self): - return self.commit.hexsha[0:7] - - def _prefix_from_branch(self): - """Determine the X.Y semver prefix for the branch name. - - :return prefix (str): Two-digit semver prefix corresponding to the branch. - - If the branch name is of the form [remote/]mce-X.Y, this will be X.Y. - - If the branch name is [remote/]master, we'll use the master prefix. - - Otherwise, we'll use the "unknown" default. - """ - m = MCE_BRANCH_RE.match(self._branch_name) - if m: - return m.group(2) - - m = MASTER_BRANCH_RE.match(self._branch_name) - if m: - return MASTER_BRANCH_PREFIX - - return UNKNOWN_BRANCH_PREFIX - - def _find_branch(self, branch_name: str): - # The user may have specified a branch name for which we don't have a local ref - # (e.g. `mce-2.1`). Rather than forcing them to specify a qualified ref, we'll - # automatically look for it in the `upstream` and `origin` remotes as well. - for remote in ("", "upstream/", "origin/"): - branch = remote + branch_name - log(f"Trying to find {branch_name} at {branch}") - try: - commit = self.repo.rev_parse(branch) - except git.BadName: - log(f"Couldn't find {branch_name} at `{branch}`") - else: - log(f"Found {branch_name} at `{branch}`") - break - else: - log(f"Couldn't find {branch_name} branch!", level="fatal") - return commit - - @property - def semver(self): - return f"{self._prefix}.{self._commit_count}-{self.shortsha}" - - def __str__(self) -> str: - return f"v{self.semver}" - - -def log(*args, level="info", **kwargs): - if _mode == "standalone": - print(*args, file=sys.stderr, **kwargs) - else: - print(*args, **kwargs) - if level == "fatal": - sys.exit(1) - - -_mode = "library" - -if __name__ == "__main__": - _mode = "standalone" - repo = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) - print(str(Version(repo))) diff --git a/hack/version2.sh b/hack/version2.sh new file mode 100755 index 00000000000..1607f2d21c9 --- /dev/null +++ b/hack/version2.sh @@ -0,0 +1,317 @@ +#!/bin/bash + +set -euo pipefail + +# Match things like 'mce-2.0' or origin/mce-2.0, capturing: +# 1: 'origin/' +# 2: '2.0' (used for the bundle semver prefix) +readonly MCE_BRANCH_RE='^([^/]+/)?mce-([[:digit:]]+\.[[:digit:]]+)$' + +readonly MASTER_BRANCH_RE='^([^/]+/)?master$' + +# MASTER_BRANCH_PREFIX is the prefix of the Hive version that will be constructed by +# this script if we are tracking the master branch. +# The version used for images and bundles will be: +# "v{prefix}.{number of commits}-{git hash}" +# e.g. "v1.2.3187-18827f6" +readonly MASTER_BRANCH_PREFIX="1.2" + +# UNKNOWN_BRANCH_PREFIX is the fallback if we can't determine an MCE or master branch +readonly UNKNOWN_BRANCH_PREFIX="0.0" + +# Global state +MODE="library" +COMMIT="" +BRANCH_NAME="" +PREFIX="" +COMMIT_COUNT="" + +# Logging function +log() { + local level="$1" + shift + local message="$*" + + if [[ "$MODE" == "standalone" ]]; then + echo "$message" >&2 + else + echo "$message" + fi + + if [[ "$level" == "fatal" ]]; then + exit 1 + fi +} + +# Get short SHA (7 characters) +shortsha() { + git rev-parse --short=7 "$COMMIT" 2>/dev/null +} + +# Determine the X.Y semver prefix for the branch name. +# +# Returns: Two-digit semver prefix corresponding to the branch. +# - If the branch name is of the form [remote/]mce-X.Y, this will be X.Y. +# - If the branch name is [remote/]master, we'll use the master prefix. +# - Otherwise, we'll use the "unknown" default. +prefix_from_branch() { + local branch_name="$1" + + # Match MCE branch pattern + if [[ "$branch_name" =~ $MCE_BRANCH_RE ]]; then + echo "${BASH_REMATCH[2]}" + return 0 + fi + + # Match master branch pattern + if [[ "$branch_name" =~ $MASTER_BRANCH_RE ]]; then + echo "$MASTER_BRANCH_PREFIX" + return 0 + fi + + # Default to unknown + echo "$UNKNOWN_BRANCH_PREFIX" +} + +# The user may have specified a branch name for which we don't have a local ref +# (e.g. `mce-2.1`). Rather than forcing them to specify a qualified ref, we'll +# automatically look for it in the `upstream` and `origin` remotes as well. +find_branch() { + local branch_name="$1" + local remote + + for remote in "" "upstream/" "origin/"; do + local branch="${remote}${branch_name}" + log "info" "Trying to find $branch_name at $branch" + + if git rev-parse --verify --quiet "$branch" >/dev/null 2>&1; then + log "info" "Found $branch_name at \`$branch\`" + git rev-parse "$branch" + return 0 + else + log "info" "Couldn't find $branch_name at \`$branch\`" + fi + done + + log "fatal" "Couldn't find $branch_name branch!" +} + +# Check if commit1 is ancestor of commit2 +is_ancestor() { + local ancestor="$1" + local descendant="$2" + git merge-base --is-ancestor "$ancestor" "$descendant" 2>/dev/null +} + +# Ensure the named branch is related to (at, an ancestor of, or descended from) our commit. +# +# Param: branch_name - A branch name. As a convenience, if not fully qualified, and no such +# branch exists locally, we will try to find it at origin/ and upstream/. +# Returns: The branch name. +# Error: If the named branch is not related to our commit. +validate_branch() { + local branch_name="$1" + + local branch_commit + branch_commit=$(find_branch "$branch_name") + + if [[ "$branch_commit" == "$COMMIT" ]]; then + log "debug" "Branch matches commit" + echo "$branch_name" + return 0 + fi + + if is_ancestor "$COMMIT" "$branch_commit"; then + log "debug" "Commit is an ancestor of branch: you are requesting a version for an old commit!" + echo "$branch_name" + return 0 + fi + + if is_ancestor "$branch_commit" "$COMMIT"; then + log "debug" "Branch is an ancestor of commit: you are requesting a version for an unmerged commit!" + echo "$branch_name" + return 0 + fi + + # Die + local short_commit short_branch + short_commit=$(git rev-parse --short=8 "$COMMIT") + short_branch=$(git rev-parse --short=8 "$branch_commit") + log "fatal" "Commit $short_commit and branch $branch_name ($short_branch) do not appear to be related!" +} + +branch_from_commit() { + local commit_ish="${1:-}" + + local -a here=() + local -a ancestors=() + local -a descendants=() + + # If we got an explicit commit_ish, and it's already a branch name, use it. + if [[ -n "$commit_ish" ]]; then + # Exact match + if git show-ref --verify --quiet "refs/heads/$commit_ish" 2>/dev/null; then + log "debug" "Found a branch for commit_ish $commit_ish" + echo "$commit_ish" + return 0 + fi + + # Match minus remote name + while IFS= read -r ref; do + local remote_head + if [[ "$ref" =~ refs/remotes/([^/]+)/(.+)$ ]]; then + local remote_name="${BASH_REMATCH[1]}" + remote_head="${BASH_REMATCH[2]}" + + if [[ "$remote_head" == "$commit_ish" ]]; then + log "debug" "Found a branch for commit_ish $commit_ish at remote '$remote_name'" + echo "$commit_ish" + return 0 + fi + fi + done < <(git for-each-ref --format='%(refname)' refs/remotes/ 2>/dev/null) + fi + + log "debug" "Trying to discover a suitable branch from commit $(shortsha)..." + + while IFS= read -r ref; do + local refname ref_commit + + # Extract reference name + if [[ "$ref" =~ ^refs/remotes/[^/]+/(.+)$ ]]; then + refname="${BASH_REMATCH[1]}" + elif [[ "$ref" =~ ^refs/heads/(.+)$ ]]; then + refname="${BASH_REMATCH[1]}" + else + continue + fi + + # Skip HEAD and konflux branches + [[ "$refname" == "HEAD" ]] && continue + [[ "$refname" =~ konflux/ ]] && continue + + ref_commit=$(git rev-parse "$ref" 2>/dev/null) + + # Okay, now start using $COMMIT, which is already rev_parse()d. + # If this ref is at our commit, it's a candidate + if [[ "$ref_commit" == "$COMMIT" ]]; then + here+=("$refname") + elif is_ancestor "$ref_commit" "$COMMIT"; then + ancestors+=("$refname") + elif is_ancestor "$COMMIT" "$ref_commit"; then + descendants+=("$refname") + fi + done < <(git for-each-ref --format='%(refname)' refs/heads/ refs/remotes/ 2>/dev/null) + + # First look for a unique branch right here + if [[ ${#here[@]} -eq 1 ]]; then + log "debug" "Found unique branch ${here[0]} at commit $(shortsha)" + echo "${here[0]}" + return 0 + fi + + if [[ ${#here[@]} -gt 1 ]]; then + # We can't handle this + log "fatal" "Found ${#here[@]} branches at commit $(shortsha)! Please specify a branch name explicitly." + fi + + # Next look for named descendants of our commit. This indicates we're versioning an old commit on the branch. + if [[ ${#descendants[@]} -eq 1 ]]; then + log "debug" "Found branch ${descendants[0]} descended from commit $(shortsha)" + echo "${descendants[0]}" + return 0 + fi + + log "debug" "descendants: ${descendants[*]}" + + if [[ ${#descendants[@]} -eq 0 ]]; then + log "warning" "WARNING: Are you versioning an unmerged commit?" + fi + + if [[ ${#ancestors[@]} -eq 1 ]]; then + log "debug" "Found branch ${ancestors[0]} which is an ancestor of commit $(shortsha)" + echo "${ancestors[0]}" + return 0 + fi + + log "fatal" "Could not determine a branch! Please specify one explicitly." +} + +# Version initialization +version_init() { + local branch_name_arg="${1:-}" + local commit_ish_arg="${2:-}" + + # Determine commit + if [[ -n "$commit_ish_arg" ]]; then + # Commit explicitly given + COMMIT=$(git rev-parse "$commit_ish_arg") + else + # Assume HEAD. If we got branch_name but not commit_ish, and they're sitting somewhere unrelated, + # that's a user error. (To build on the branch commit, just specify the branch to commit_ish.) + COMMIT=$(git rev-parse HEAD) + fi + + # Determine branch name + if [[ -n "$branch_name_arg" ]]; then + BRANCH_NAME=$(validate_branch "$branch_name_arg") + else + # Before looking for related refs: + # If we have an active branch, and it's equal to our commit, use it. + if git symbolic-ref -q HEAD >/dev/null 2>&1; then + local active_branch + active_branch=$(git rev-parse --abbrev-ref HEAD) + + if [[ "$(git rev-parse HEAD)" == "$COMMIT" ]]; then + BRANCH_NAME="$active_branch" + log "debug" "Using active branch $BRANCH_NAME since it corresponds to commit $(shortsha)" + fi + else + log "debug" "No active branch -- detached HEAD?" + fi + + # If still no branch name, discover it + if [[ -z "$BRANCH_NAME" ]]; then + BRANCH_NAME=$(branch_from_commit "$commit_ish_arg") + fi + fi + + # Calculate prefix and commit count + PREFIX=$(prefix_from_branch "$BRANCH_NAME") + local parent + parent=$(git rev-list --max-parents=0 "$COMMIT") + COMMIT_COUNT=$(git rev-list --count "${parent}..${COMMIT}") +} + +# Get semver string +semver() { + echo "${PREFIX}.${COMMIT_COUNT}-$(shortsha)" +} + +# String representation +version_string() { + echo "v$(semver)" +} + +# Main +main() { + MODE="standalone" + + # Get repo directory (parent of hack/) + local repo_dir + repo_dir=$(dirname "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")") + + # Change to repo directory + cd "$repo_dir" + + # Initialize version + version_init + + # Print version string + version_string +} + +# Run main if executed directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main +fi From 9b27aa823a9e7cd2802fe04ed8b1476203c21211 Mon Sep 17 00:00:00 2001 From: Suhani Mehta Date: Wed, 11 Mar 2026 14:41:31 -0400 Subject: [PATCH 2/2] Update Makefile Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d2943496091..3e15fa7ea71 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,7 @@ endif # Note that building against a local commit may result in {major}.{minor} being rendered as # 0.0.x-y if it is an `UnknownBranch`. However, the {commitcount} and {sha} # should still be accurate. -SOURCE_GIT_TAG := v$(shell hack/version2.sh) +SOURCE_GIT_TAG := $(shell hack/version2.sh) BINDATA_INPUTS :=./config/sharded_controllers/... ./config/hiveadmission/... ./config/controllers/... ./config/rbac/... ./config/configmaps/... $(call add-bindata,operator,$(BINDATA_INPUTS),,assets,pkg/operator/assets/bindata.go)