diff --git a/.ci-operator.yaml b/.ci-operator.yaml index 99e1a831b..188626d79 100644 --- a/.ci-operator.yaml +++ b/.ci-operator.yaml @@ -2,8 +2,3 @@ build_root_image: name: boilerplate namespace: openshift tag: image-v8.3.6 -tests: -- as: precommit-check - commands: echo "pre-commit is for local developer use only. CI is the authoritative gate." - container: - from: src diff --git a/.claude/skills/prow-ci/SKILL.md b/.claude/skills/prow-ci/SKILL.md index 262edbffc..14b5e9465 100644 --- a/.claude/skills/prow-ci/SKILL.md +++ b/.claude/skills/prow-ci/SKILL.md @@ -4,7 +4,7 @@ description: Fetch and analyze OpenShift Prow CI job failures with automated art trigger: prow, prow-ci, /prow-ci, ci results, check ci, analyze ci failure --- -# Prow CI Analysis for Addon Operator +# Prow CI Analysis for Addon Operator This skill fetches Prow CI job artifacts from Google Cloud Storage and provides automated failure analysis. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4fa46a1ce..38c178698 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,8 +6,13 @@ updates: labels: - "area/dependency" - "ok-to-test" + - "lgtm" + - "approved" schedule: interval: "weekly" + day: "monday" + time: "03:00" + timezone: "UTC" ignore: - dependency-name: "redhat-services-prod/openshift/boilerplate" # don't upgrade boilerplate via these means diff --git a/.github/renovate.json b/.github/renovate.json index fcc5e604e..d4eb46e3f 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -2,5 +2,9 @@ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "github>openshift/boilerplate//.github/renovate.json" + ], + "enabledManagers": [ + "tekton", + "gomod" ] } diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ea603cf18..5c525e17c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,11 +1,3 @@ -exclude: | - (?x)( - (^vendor/)| - (.deepcopy.go$)| - (mage_output_file.go$)| - (.claude/settings.json$) - ) - # ============================================================================= # Tier 1 — Common Pre-Commit Hooks for OSD Operators # SREP-4485 | Golden rules: SREP-4450 @@ -54,6 +46,14 @@ exclude: | # # ============================================================================= +exclude: | + (?x)( + (^vendor/)| + (.deepcopy.go$)| + (mage_output_file.go$)| + (.claude/settings.json$) + ) + repos: # --------------------------------------------------------------------------- @@ -67,8 +67,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 # pinned immutable tag hooks: - - id: check-added-large-files - args: [--maxkb=500] - id: check-merge-conflict - id: trailing-whitespace args: [--markdown-linebreak-ext=md] @@ -89,16 +87,17 @@ repos: - id: gitleaks # --------------------------------------------------------------------------- - # 3. STATIC ANALYSIS | target < 15s cached | error - # Mirrors ci/prow/lint: go-check exactly (same version + config as CI). - # Linter config: boilerplate/openshift/golang-osd-operator/golangci.yml - # --------------------------------------------------------------------------- - # --------------------------------------------------------------------------- - # NOTE: golangci-lint runs as a local system hook (language: system) to - # use the pre-installed binary from the boilerplate image in CI. This - # avoids building golangci-lint from source (slow, cold-cache timeout). - # Locally, ensure golangci-lint is installed: https://golangci-lint.run + # 3. STATIC ANALYSIS — ci/prow/lint runs go-check; skip golangci in PRE_COMMIT_CI + # (image already has golangci; upstream hook builds from source and flakes). # --------------------------------------------------------------------------- + - repo: local + hooks: + - id: golangci-lint + name: golangci-lint + language: system + entry: bash -c 'test -n "${PRE_COMMIT_CI:-}" && exit 0; golangci-lint run --config=boilerplate/openshift/golang-osd-operator/golangci.yml --timeout=120s ./...' + types: [go] + pass_filenames: false # --------------------------------------------------------------------------- # Local hooks — compile, dependency, security @@ -110,19 +109,6 @@ repos: # --------------------------------------------------------------------------- - repo: local hooks: - - id: golangci-lint - name: golangci-lint - language: system - entry: bash -c 'test -n "${PRE_COMMIT_CI:-}" && exit 0; golangci-lint run --new-from-rev HEAD --fix --config=boilerplate/openshift/golang-osd-operator/golangci.yml --timeout=120s' - types: [go] - require_serial: true - pass_filenames: false - - - id: go-fmt - name: go fmt - language: system - entry: bash -c "T=$(command -v timeout || command -v gtimeout || echo); ${T:+$T 30s} gofmt -s -w "$@"" -- - types: [go] # ----------------------------------------------------------------------- # 4. COMPILE CHECK | target < 10s cached | error @@ -137,14 +123,7 @@ repos: types: [go] pass_filenames: false - # ----------------------------------------------------------------------- - # 5. DEPENDENCY DRIFT | target < 120s cold cache | error - # Detects uncommitted go.mod changes after go mod tidy. - # go.sum is intentionally excluded from the diff check: checksums - # are environment-specific (Go version, platform) and go.sum drift - # does not indicate a missing 'go mod tidy' run. - # Fix: run 'go mod tidy' and stage go.mod. - # ----------------------------------------------------------------------- + # 5. DEPENDENCY DRIFT — go.mod only (go.sum varies by Go version in CI) - id: go-mod-tidy name: go mod tidy language: system diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index 3933abdaa..bf1a91d0c 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -26,7 +26,6 @@ aliases: - cjnovak98 srep-functional-team-hulk: - ravitri - - devppratik - Tafhim - tkong-redhat - TheUndeadKing @@ -81,9 +80,12 @@ aliases: - ravitri srep-team-leads: - rafael-azevedo - - iamkirkbater - dustman9000 - bmeng - typeid + sre-group-leads: + - apahim + - maorfr + - rogbas srep-architects: - cblecker diff --git a/boilerplate/_data/last-boilerplate-commit b/boilerplate/_data/last-boilerplate-commit index 0cf78c651..5a5237535 100644 --- a/boilerplate/_data/last-boilerplate-commit +++ b/boilerplate/_data/last-boilerplate-commit @@ -1 +1 @@ -dd0c8513538cbc8e2c9df5ce3c2053740d733f34 +ae0fd36814256630d6cc5e32672d72d2cf2a7b04 diff --git a/boilerplate/_lib/container-make b/boilerplate/_lib/container-make index 77834586d..8da20031a 100755 --- a/boilerplate/_lib/container-make +++ b/boilerplate/_lib/container-make @@ -29,12 +29,14 @@ if [[ "${CONTAINER_ENGINE##*/}" == "podman" ]] && [[ $OSTYPE == *"linux"* ]]; th else CE_OPTS="${CE_OPTS} -v $REPO_ROOT:$CONTAINER_MOUNT" fi -container_id=$($CONTAINER_ENGINE run -d ${CE_OPTS} $IMAGE_PULL_PATH sleep infinity) +container_id=$($CONTAINER_ENGINE run --rm -d ${CE_OPTS} $IMAGE_PULL_PATH sleep infinity) if [[ $? -ne 0 ]] || [[ -z "$container_id" ]]; then err "Couldn't start detached container" fi +trap "$CONTAINER_ENGINE stop $container_id >/dev/null 2>&1" EXIT + # Now run our `make` command in it with the right UID and working directory args="exec -it -u $(id -u):0 -w $CONTAINER_MOUNT $container_id" banner "Running: make $@" @@ -52,6 +54,9 @@ if [[ $rc -ne 0 ]]; then fi fi +# Disarm the interrupt trap -- normal cleanup handles it from here +trap - EXIT + # Finally, remove the container banner "Cleaning up the container" $CONTAINER_ENGINE rm -f $container_id >/dev/null diff --git a/boilerplate/_lib/subscriber-propose-update b/boilerplate/_lib/subscriber-propose-update index f3b06ef20..4ac512569 100755 --- a/boilerplate/_lib/subscriber-propose-update +++ b/boilerplate/_lib/subscriber-propose-update @@ -25,7 +25,7 @@ Quirks and Limitations: - Is still slightly interactive, because 'gh pr create' likes to ask questions about your origin and upstream. EOF - exit -1 + exit 1 } source $REPO_ROOT/boilerplate/_lib/subscriber.sh @@ -34,47 +34,101 @@ source $REPO_ROOT/boilerplate/_lib/subscriber.sh [[ $# -eq 0 ]] && usage TMPD=$(mktemp -d) +echo $TMPD; trap "rm -fr $TMPD" EXIT +run_step() { + local title=$1 + local log_file="$TMPD/$title.log" + log_file=$(tr '[:upper:]' '[:lower:]' <<< "$log_file") + log_file=$(tr ' ' '-' <<< "$log_file") + shift + + if [[ $1 != "--" ]]; then + echo "ERR: expected '--' but got '$1'" + exit 1 + fi + shift + echo -n "$title... " + + if ! "$@" > "$log_file" 2>&1; then + echo " FAILED" + echo "!!!" + echo "!!! Boilerplate update failed for $subscriber" + echo "!!!" + echo "" + cat "$log_file" + exit 1 + fi + echo " DONE" +} + +sync_main() { + local main_branch=$1 + shift + + git pull upstream $main_branch + git push origin $main_branch +} + +git_clean_and_push() { + local branch=$1 + shift + + git push --delete origin $branch || true + git push -u origin $branch +} + propose_update() { local subscriber=$1 local proj=${subscriber#*/} - if [[ -z "$DRY_RUN" ]]; then - echo "DRY RUN: Would propose update for $subscriber" - return 0 - fi - ( # Clone my fork of the subscriber repo cd $TMPD # This # - uses the existing fork if one exists # - sets 'origin' and 'upstream' remotes - gh repo fork $subscriber --clone=true --remote=true + # only clones the default branch to save disk space and time + + run_step "Creating fork" -- gh repo fork $subscriber --clone=true --default-branch-only cd $proj - # Current branch is 'master' or 'main' - cur_branch=$(current_branch .) - # Make sure our origin is synced with upstream, so our update - # commit is based off of the latest code. - # WARNING: This changes your fork! - git pull upstream $cur_branch - git push origin $cur_branch - - # Create the update commit - make boilerplate-update - make boilerplate-commit - - # And create the PR - # TODO: This is interactive. How do we tell gh "Yes, please use - # upstream as upstream and origin as origin?" - gh pr create -f + # Current branch is 'master' or 'main' or 'trunk' + main_branch=$(current_branch .) + run_step "Syncing Fork" -- sync_main $main_branch + # run_step "Pushing fork" -- git push origin $main_branch + + # Create the update commit - only cat logs if something goes wrong. + run_step "Updating boilerplate" -- make boilerplate-update + run_step "Committing boilerplate update" -- make boilerplate-commit + + boilerplate_branch=$(git rev-parse --abbrev-ref HEAD) + # By pushing to the origin boilerplate branch explicitly before opening a PR, + # we make don't get prompted for the branch to push to. + # If we still find that it's giving us an interactive prompt, we can otherwise + # use `gh api` to create the PR programmatically. + if [[ "$boilerplate_branch" == "$main_branch" ]]; then + echo "CRITICAL ERROR: boilerplate branch '$boilerplate_branch' is the same as main branch '$main_branch'" + echo "If you see this, something has gone terribly wrong" + echo "Skipping" + exit 20 + fi + run_step "pushing update" -- git_clean_and_push $boilerplate_branch + + gh pr create --repo $subscriber -f $DRY_RUN_FLAG ) } bp_master=$(git rev-parse master) +DRY_RUN_FLAG="" +if [[ -z "$DRY_RUN" ]]; then + echo "DRY RUN: ENABLED" + DRY_RUN_FLAG="--dry-run" +fi + + for subscriber in $(subscriber_args "$@"); do # Does this one need an update? @@ -89,14 +143,45 @@ for subscriber in $(subscriber_args "$@"); do continue fi - # Is there already a PR proposed for this level? - existing_pr=$(gh pr list --repo $subscriber | grep -P ":boilerplate-\S+-$bp_master\s") + # Is there already a PR proposed for this commit? + pr_list=$(gh pr list --repo $subscriber --json headRefName,url,number | jq -r '. | map(select(.headRefName | startswith("boilerplate-update--")))') + existing_pr=$(jq -r ".[] | select(.headRefName == \"boilerplate-update--$bp_master\")" <<< "$pr_list") if [[ -n "$existing_pr" ]]; then - echo "Subscriber '$subscriber' already has an open PR:" - echo "https://github.com/$subscriber/pull/$existing_pr" + echo "Subscriber '$subscriber' already has an open PR for this boilerplate commit:" + jq -r .url <<< "$existing_pr" continue fi # Pull the trigger - propose_update "$subscriber" + if ! propose_update "$subscriber"; then + echo "Error: failed to propose update for '$subscriber'" + continue + fi + + new_pr="XXXX" + # Get the new PR URL + # only run if not dry-run - otherwise the new_pr var will be empty + if [[ -n $DRY_RUN ]]; then + new_pr=$(gh pr list --repo $subscriber --json headRefName,number | jq -r ".[] | select(.headRefName == \"boilerplate-update--$bp_master\") | .number") + if [[ -z "$new_pr" ]]; then + echo "error: unable to find new PR for boilerplate update '$bp_master' on subscriber '$subscriber'" + continue + fi + fi + + # Add comments to existing PRs to say they're superseded by this new one + if [[ -n "$pr_list" ]]; then + prs=$(jq -r '. | map(.number) | @tsv' <<< "$pr_list") + echo "Closing old PRs: $prs" + for pr in $prs; do + if [[ -z $DRY_RUN ]]; then + echo "Dry run - would close $pr with comment:" + echo " \"Superseded by #$new_pr.\"" + continue + fi + + gh pr close --repo $subscriber --comment "Superseded by #$new_pr." $pr + done + fi + done diff --git a/boilerplate/openshift/golang-osd-operator/OWNERS_ALIASES b/boilerplate/openshift/golang-osd-operator/OWNERS_ALIASES index 7fddbfa2f..bf1a91d0c 100644 --- a/boilerplate/openshift/golang-osd-operator/OWNERS_ALIASES +++ b/boilerplate/openshift/golang-osd-operator/OWNERS_ALIASES @@ -26,7 +26,6 @@ aliases: - cjnovak98 srep-functional-team-hulk: - ravitri - - devppratik - Tafhim - tkong-redhat - TheUndeadKing @@ -81,7 +80,6 @@ aliases: - ravitri srep-team-leads: - rafael-azevedo - - iamkirkbater - dustman9000 - bmeng - typeid diff --git a/boilerplate/openshift/golang-osd-operator/dependabot.yml b/boilerplate/openshift/golang-osd-operator/dependabot.yml index fee161097..eae3de413 100644 --- a/boilerplate/openshift/golang-osd-operator/dependabot.yml +++ b/boilerplate/openshift/golang-osd-operator/dependabot.yml @@ -9,6 +9,9 @@ updates: - "approved" schedule: interval: "weekly" + day: "monday" + time: "03:00" + timezone: "UTC" ignore: - dependency-name: "redhat-services-prod/openshift/boilerplate" # don't upgrade boilerplate via these means diff --git a/build/Dockerfile b/build/Dockerfile index 746fd5205..a2a2db724 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -11,7 +11,7 @@ RUN make go-build RUN GOOS=linux CGO_ENABLED=1 GOARCH=amd64 GOFLAGS="" go build -o build/_output/bin/addon-operator-webhook ./cmd/addon-operator-webhook ### -FROM registry.access.redhat.com/ubi9/ubi-minimal:9.8-1779809423 +FROM registry.access.redhat.com/ubi9/ubi-minimal:9.8-1780378819 ENV USER_UID=1001 \ USER_NAME=addon-operator diff --git a/build/Dockerfile.olm-registry b/build/Dockerfile.olm-registry index 7b5899ea7..408bc99d5 100644 --- a/build/Dockerfile.olm-registry +++ b/build/Dockerfile.olm-registry @@ -4,7 +4,7 @@ COPY ${SAAS_OPERATOR_DIR} manifests RUN initializer --permissive # ubi-micro does not work for clusters with fips enabled unless we make OpenSSL available -FROM registry.access.redhat.com/ubi9/ubi-minimal:9.8-1779809423 +FROM registry.access.redhat.com/ubi9/ubi-minimal:9.8-1780378819 COPY --from=builder /bin/registry-server /bin/registry-server COPY --from=builder /bin/grpc_health_probe /bin/grpc_health_probe diff --git a/build/Dockerfile.webhook b/build/Dockerfile.webhook index a24064ebe..2be1555a6 100644 --- a/build/Dockerfile.webhook +++ b/build/Dockerfile.webhook @@ -12,7 +12,7 @@ COPY . . RUN GOOS=linux CGO_ENABLED=1 GOARCH=amd64 GOFLAGS="" go build -o build/_output/bin/addon-operator-webhook ./cmd/addon-operator-webhook ### -FROM registry.access.redhat.com/ubi9/ubi-minimal:9.8-1779809423 +FROM registry.access.redhat.com/ubi9/ubi-minimal:9.8-1780378819 ENV USER_UID=1001 \ USER_NAME=addon-operator