Skip to content
Open
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
179 changes: 179 additions & 0 deletions .github/workflows/update-go-version.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
name: Update Go Version

on:
workflow_call:
inputs:
version-schema:
description: >
Version schema key matching a file in go-versions/ (e.g. "ocp-4.21").
The workflow fetches go-versions/<version-schema>.yaml from medik8s/.github
to determine the Go version and CI operator image.
required: true
type: string
dry-run:
description: "If true, only show what would change without creating a PR"
required: false
default: false
type: boolean

permissions:
contents: write
pull-requests: write

jobs:
update-go:
name: Update Go version
runs-on: ubuntu-24.04
steps:
- name: Checkout operator repo
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Fetch version config from medik8s/.github
id: config
env:
VERSION_SCHEMA: ${{ inputs.version-schema }}
run: |
CONFIG_URL="https://raw.githubusercontent.com/medik8s/.github/main/go-versions/${VERSION_SCHEMA}.yaml"
HTTP_CODE=$(curl -sL -w "%{http_code}" -o /tmp/go-version.yaml "${CONFIG_URL}")
if [ "${HTTP_CODE}" != "200" ]; then
echo "::error::Version schema '${VERSION_SCHEMA}' not found at ${CONFIG_URL} (HTTP ${HTTP_CODE})"
exit 1
fi

# Parse simple key: "value" YAML without yq (not pre-installed on runners)
GO_VERSION=$(grep '^go:' /tmp/go-version.yaml | sed 's/^go: *"\?\([^"]*\)"\?/\1/')
CI_IMAGE=$(grep '^ci-operator-image:' /tmp/go-version.yaml | sed 's/^ci-operator-image: *"\?\([^"]*\)"\?/\1/')
Comment thread
razo7 marked this conversation as resolved.

if [ -z "${GO_VERSION}" ] || [ -z "${CI_IMAGE}" ]; then
echo "::error::Failed to parse version config — go='${GO_VERSION}' ci-image='${CI_IMAGE}'"
cat /tmp/go-version.yaml
exit 1
fi

echo "go=${GO_VERSION}" >> "${GITHUB_OUTPUT}"
echo "ci-image=${CI_IMAGE}" >> "${GITHUB_OUTPUT}"
echo "Go version: ${GO_VERSION}"
echo "CI image: ${CI_IMAGE}"

- name: Check if update needed
id: check
env:
TARGET_GO: ${{ steps.config.outputs.go }}
TARGET_CI_IMAGE: ${{ steps.config.outputs.ci-image }}
run: |
CURRENT_GO=$(grep '^go ' go.mod | awk '{print $2}')
HAS_TOOLCHAIN=$(grep -c '^toolchain ' go.mod || true)

# Detect if go.mod needs changes:
# - Version mismatch (e.g. 1.24 -> 1.25)
# - Needs normalization (e.g. 1.25.0 -> 1.25)
# - Has toolchain directive that should be removed
if [ "${CURRENT_GO}" != "${TARGET_GO}" ] || [ "${HAS_TOOLCHAIN}" -gt 0 ]; then
echo "go-update=true" >> "${GITHUB_OUTPUT}"
echo "Go update needed: '${CURRENT_GO}' -> '${TARGET_GO}' (toolchain present: ${HAS_TOOLCHAIN})"
else
echo "go-update=false" >> "${GITHUB_OUTPUT}"
echo "Go version already at ${TARGET_GO}, no toolchain directive"
fi

if [ -f .ci-operator.yaml ]; then
CURRENT_IMAGE=$(grep '^ *tag:' .ci-operator.yaml | head -1 | sed 's/.*tag: *"\?\([^"]*\)"\?/\1/')
if [ "${CURRENT_IMAGE}" = "${TARGET_CI_IMAGE}" ]; then
echo "CI image already at ${TARGET_CI_IMAGE}"
echo "ci-update=false" >> "${GITHUB_OUTPUT}"
else
echo "CI image update needed: ${CURRENT_IMAGE} -> ${TARGET_CI_IMAGE}"
echo "ci-update=true" >> "${GITHUB_OUTPUT}"
fi
Comment on lines +81 to +89

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

grep will capture multiple tags, breaking the evaluation.

Using grep 'tag:' captures all occurrences of tag: in .ci-operator.yaml (e.g., tags often found under base_images configurations). This produces a multiline string in CURRENT_IMAGE, which causes the equality check [ "${CURRENT_IMAGE}" = "${TARGET_CI_IMAGE}" ] to silently fail, forcing an unnecessary update attempt.

Use the pre-installed yq tool to precisely extract the builder image tag.

🐛 Proposed fix
           if [ -f .ci-operator.yaml ]; then
-            CURRENT_IMAGE=$(grep 'tag:' .ci-operator.yaml | sed 's/.*tag: *"\?\([^"]*\)"\?/\1/')
+            CURRENT_IMAGE=$(yq '.build_root.image_stream_tag.tag' .ci-operator.yaml)
             if [ "${CURRENT_IMAGE}" = "${TARGET_CI_IMAGE}" ]; then
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [ -f .ci-operator.yaml ]; then
CURRENT_IMAGE=$(grep 'tag:' .ci-operator.yaml | sed 's/.*tag: *"\?\([^"]*\)"\?/\1/')
if [ "${CURRENT_IMAGE}" = "${TARGET_CI_IMAGE}" ]; then
echo "CI image already at ${TARGET_CI_IMAGE}"
echo "ci-update=false" >> "${GITHUB_OUTPUT}"
else
echo "CI image update needed: ${CURRENT_IMAGE} -> ${TARGET_CI_IMAGE}"
echo "ci-update=true" >> "${GITHUB_OUTPUT}"
fi
if [ -f .ci-operator.yaml ]; then
CURRENT_IMAGE=$(yq '.build_root.image_stream_tag.tag' .ci-operator.yaml)
if [ "${CURRENT_IMAGE}" = "${TARGET_CI_IMAGE}" ]; then
echo "CI image already at ${TARGET_CI_IMAGE}"
echo "ci-update=false" >> "${GITHUB_OUTPUT}"
else
echo "CI image update needed: ${CURRENT_IMAGE} -> ${TARGET_CI_IMAGE}"
echo "ci-update=true" >> "${GITHUB_OUTPUT}"
fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/update-go-version.yaml around lines 75 - 83, Update the
CURRENT_IMAGE assignment in the .ci-operator.yaml comparison block to use the
pre-installed yq tool and extract only the builder image tag, rather than
grepping every tag entry. Preserve the existing equality check and ci-update
outputs once CURRENT_IMAGE contains the single intended value.

else
echo "No .ci-operator.yaml found, skipping CI image update"
echo "ci-update=false" >> "${GITHUB_OUTPUT}"
fi

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: "${{ steps.config.outputs.go }}"

- name: Update go.mod
if: steps.check.outputs.go-update == 'true'
env:
TARGET_GO: ${{ steps.config.outputs.go }}
run: |
# Set Go minor version only (e.g. "1.25", not "1.25.0")
go mod edit -go="${TARGET_GO}"

# Remove toolchain directive — patch versions are handled by the builder
sed -i '/^toolchain /d' go.mod
Comment on lines +106 to +109

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This contradicts how every operator actually manages Go versions. All 6 repos use patch versions with toolchain:

Repo go.mod
SNR, NHC, MDR, NMO, SBR go 1.26.0 / toolchain go1.26.5
FAR go 1.25.0 / toolchain go1.25.9

The sed removal deletes what every repo intentionally keeps, and go mod tidy (next step) will likely re-add it anyway since the installed Go patch version (e.g., 1.25.3 via setup-go) is newer than go 1.25 (equivalent to 1.25.0).

Recommendation: keep toolchain and update the schema to include the patch version:

# go-versions/latest.yaml
go: "1.26.5"          # full patch version
ci-operator-image: "rhel-9-release-golang-1.26-openshift-5.0"

Then replace these lines with:

go mod edit -go="${TARGET_GO}" -toolchain="go${TARGET_GO}"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged, will address in a follow-up — need to update the schema to include patch versions first.


- name: Update dependencies
run: |
# Always run tidy + vendor to pick up dependency security patches,
# even when the Go version itself hasn't changed
go mod tidy

if [ -d vendor ]; then
go mod vendor
fi
Comment on lines +113 to +119

@razo7 razo7 Aug 17, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two issues here:

1. go mod tidy doesn't update dependency versions — it adds missing and removes unused modules, but won't pull in security patches. Every actual Go bump PR (NHC #421, SNR #324, etc.) includes explicit dependency bumps like golang.org/x/net v0.53.0 → v0.57.0.

It's fine to keep this PR focused on Go + go.sum only, but as a follow-up consider extending the version schema to cover packages, tools, and test framework alignment:

# go-versions/latest.yaml
go: "1.26.5"
ci-operator-image: "rhel-9-release-golang-1.26-openshift-5.0"
packages:
  - golang.org/x/net@latest
  - golang.org/x/sys@latest
  # K8s packages follow release branches matching OCP version
  - k8s.io/api@release-0.32
  - k8s.io/client-go@release-0.32
tools:
  kustomize: latest           # auto-resolve from GitHub releases
  controller-gen: latest
  ginkgo: "2.23.4"            # must match go.mod
  gomega: "1.37.1"            # must match go.mod

Key design points:

  • Auto-discovery: a helper workflow that queries GitHub releases API and Go module proxy to generate/update this config — so you don't have to look up versions manually
  • Release branch targeting: K8s packages (k8s.io/api, client-go) need @release-0.XX matching the OCP version, not @latest
  • Ginkgo/gomega alignment: Makefile GINKGO_VERSION and go.mod github.com/onsi/ginkgo/v2 must stay in sync — a centralized config that bumps both in one pass prevents drift

2. All 6 operators (excluding CUR) have go-verify or equivalent Makefile targets that run go mod tidy + go mod vendor + go mod verify. Consider calling make go-verify instead of raw tidy/vendor — 5/6 repos use go-verify; NHC uses vendor (can be aligned separately).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestions for follow-up — keeping this PR focused on Go version + go.sum for now.


- name: Update .ci-operator.yaml
if: steps.check.outputs.ci-update == 'true'
env:
TARGET_CI_IMAGE: ${{ steps.config.outputs.ci-image }}
run: |
sed -i "s|^\( tag: \).*|\1${TARGET_CI_IMAGE}|" .ci-operator.yaml

Comment on lines +125 to +127

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Incorrect indentation assumption in sed replacement.

The regex ^\( tag: \) strictly expects two spaces of indentation. In OpenShift .ci-operator.yaml files, the tag field under build_root is typically indented with four spaces ( tag:). Consequently, this sed command will silently fail to update the file, submitting a PR without the expected CI image change. Additionally, if other configuration blocks (like base_images) happen to use two-space indentation for their tags, they will be incorrectly corrupted.

Use yq to safely update the exact field.

🐛 Proposed fix
         env:
           TARGET_CI_IMAGE: ${{ steps.config.outputs.ci-image }}
         run: |
-          sed -i "s|^\(  tag: \).*|\1${TARGET_CI_IMAGE}|" .ci-operator.yaml
+          yq -i '.build_root.image_stream_tag.tag = env(TARGET_CI_IMAGE)' .ci-operator.yaml
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: |
sed -i "s|^\( tag: \).*|\1${TARGET_CI_IMAGE}|" .ci-operator.yaml
run: |
yq -i '.build_root.image_stream_tag.tag = env(TARGET_CI_IMAGE)' .ci-operator.yaml
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/update-go-version.yaml around lines 119 - 121, Replace the
sed-based update in the workflow step with a yq expression that targets the
exact build_root.tag field in .ci-operator.yaml, assigning TARGET_CI_IMAGE while
leaving unrelated tag fields such as those under base_images unchanged.

- name: Check for changes
id: changes
run: |
if [ -z "$(git status --porcelain)" ]; then
echo "No file changes — everything is up to date"
echo "has-changes=false" >> "${GITHUB_OUTPUT}"
else
echo "has-changes=true" >> "${GITHUB_OUTPUT}"
git diff --stat
fi

- name: Verify build
if: steps.changes.outputs.has-changes == 'true'
run: |
if grep -q '^build:' Makefile 2>/dev/null; then
make build
else
go build ./...
fi

- name: Show changes (dry run)
if: inputs.dry-run && steps.changes.outputs.has-changes == 'true'
run: |
echo "=== Dry run — would create PR with these changes ==="
git diff --stat
echo "---"
git diff go.mod
echo "---"
git diff .ci-operator.yaml 2>/dev/null || true

- name: Create Pull Request
if: "!inputs.dry-run && steps.changes.outputs.has-changes == 'true'"
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7.0.11
with:
token: ${{ github.token }}
commit-message: "chore: update Go to ${{ steps.config.outputs.go }} and dependencies (${{ inputs.version-schema }})"
title: "chore: update Go to ${{ steps.config.outputs.go }} and dependencies (${{ inputs.version-schema }})"
branch: automated/go-version-update-${{ inputs.version-schema }}
delete-branch: true
body: |
Automated Go version and dependency update based on schema `${{ inputs.version-schema }}`.

**Changes:**
- Go version: `${{ steps.config.outputs.go }}`
- CI operator image: `${{ steps.config.outputs.ci-image }}`
- Toolchain directive removed (patch versions handled by builder image)
- Dependencies updated via `go mod tidy` + `go mod vendor`

This workflow runs weekly to pick up dependency security patches (CVE fixes)
even when the Go minor version hasn't changed.

**Version schema:** [`go-versions/${{ inputs.version-schema }}.yaml`](https://github.com/medik8s/.github/blob/main/go-versions/${{ inputs.version-schema }}.yaml)
47 changes: 47 additions & 0 deletions go-versions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Go Version Schemas

Each YAML file defines a Go version schema tied to an OCP release. Operator
repos reference a schema by name when calling the
[`update-go-version`](../.github/workflows/update-go-version.yaml) reusable
workflow.

## Design principles

- **`go.mod` tracks the minor version only** (e.g. `go 1.25`, not `go 1.25.0`).
- **No `toolchain` directive** — patch-level updates (`1.25.x`) are handled by
updating the CI builder image, not `go.mod`.
- **Minor version bumps** (e.g. `1.25` → `1.26`) require an explicit `go.mod`
update, which is what this workflow automates.

## Schema format

```yaml
# go-versions/ocp-4.21.yaml
go: "1.25" # Go minor version
ci-operator-image: "rhel-9-release-golang-1.25-openshift-4.21" # CI image tag
```

## Adding a new schema

When a new OCP version requires a Go bump:

1. Create `go-versions/ocp-X.Y.yaml` with the new values
2. Each operator repo updates its caller workflow to reference the new schema
3. On the next scheduled run (or manual dispatch), the workflow creates a PR

## Usage in operator repos

```yaml
# .github/workflows/go-update.yaml
name: Go Version Update
on:
schedule:
- cron: '0 8 * * 1'
workflow_dispatch:

jobs:
update:
uses: medik8s/.github/.github/workflows/update-go-version.yaml@main
with:
version-schema: ocp-4.21
```
4 changes: 4 additions & 0 deletions go-versions/ocp-4.19.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Go version schema for OCP 4.19
# Used by: older release branches (e.g. FAR release-0.5, SNR release-0.10)
go: "1.23"
ci-operator-image: "rhel-9-release-golang-1.23-openshift-4.19"
4 changes: 4 additions & 0 deletions go-versions/ocp-4.20.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Go version schema for OCP 4.20
# Used by: older release branches (e.g. FAR release-0.6, release-0.7)
go: "1.24"
ci-operator-image: "rhel-9-release-golang-1.24-openshift-4.20"
4 changes: 4 additions & 0 deletions go-versions/ocp-4.21.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Go version schema for OCP 4.21 (RHWA 25.9)
# Used by: release branches targeting OCP 4.21
go: "1.25"
ci-operator-image: "rhel-9-release-golang-1.25-openshift-4.21"
4 changes: 4 additions & 0 deletions go-versions/ocp-4.22.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Go version schema for OCP 4.22 / OCP 5.0
# Used by: main branches targeting OCP 4.22+
go: "1.26"
ci-operator-image: "rhel-9-release-golang-1.26-openshift-5.0"