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
14 changes: 10 additions & 4 deletions pkg/console/subresource/configmap/brand_ocp.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@

package configmap

const (
DEFAULT_BRAND = "ocp"
DEFAULT_DOC_URL = "https://access.redhat.com/documentation/en-us/openshift_container_platform/5.0/"
)
import "os"

const DEFAULT_BRAND = "ocp"

// DefaultDocURL returns the documentation base URL for OCP, dynamically
// deriving the version from the OPERATOR_IMAGE_VERSION environment variable.
// Falls back to "latest" if the version is unavailable or cannot be parsed.
func DefaultDocURL() string {
return formatOCPDocURL(os.Getenv("OPERATOR_IMAGE_VERSION"))
}
6 changes: 6 additions & 0 deletions pkg/console/subresource/configmap/brand_okd.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ const (
DEFAULT_BRAND = "okd"
DEFAULT_DOC_URL = "https://docs.okd.io/latest/"
)

// DefaultDocURL returns the documentation base URL for OKD.
// OKD always uses "latest", so no version derivation is needed.
func DefaultDocURL() string {
return DEFAULT_DOC_URL
}
2 changes: 1 addition & 1 deletion pkg/console/subresource/configmap/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func DefaultConfigMap(
defaultConfig, err := defaultBuilder.Host(consoleHost).
LogoutURL(defaultLogoutURL).
Brand(DEFAULT_BRAND).
DocURL(DEFAULT_DOC_URL).
DocURL(DefaultDocURL()).
APIServerURL(apiServerURL).
Monitoring(monitoringSharedConfig).
InactivityTimeout(inactivityTimeoutSeconds).
Expand Down
38 changes: 38 additions & 0 deletions pkg/console/subresource/configmap/doc_url.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package configmap

import (
"fmt"
"strconv"
"strings"
)

const ocpDocURLFormat = "https://access.redhat.com/documentation/en-us/openshift_container_platform/%s/"

// formatOCPDocURL returns the OCP documentation base URL for the given version.
// Extracts major.minor from version (e.g., "5.0.3" → "5.0"). Falls back to
// "latest" when the version is empty or cannot be parsed.
func formatOCPDocURL(version string) string {
return fmt.Sprintf(ocpDocURLFormat, extractMajorMinor(version))
}

// extractMajorMinor extracts the major.minor portion from a version string.
// Returns "latest" if the version is empty, does not contain a dot separator,
// or if the major/minor components are not valid decimal numbers.
func extractMajorMinor(version string) string {
if version == "" {
return "latest"
}
parts := strings.SplitN(version, ".", 3)
if len(parts) < 2 {
return "latest"
}
major := parts[0]
minor := parts[1]
if _, err := strconv.Atoi(major); err != nil {
return "latest"
}
if _, err := strconv.Atoi(minor); err != nil {
return "latest"
}
return major + "." + minor
}
36 changes: 36 additions & 0 deletions pkg/console/subresource/configmap/doc_url_okd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//go:build !ocp
// +build !ocp

package configmap

import "testing"

func TestDefaultDocURL(t *testing.T) {
// OKD build: DefaultDocURL always returns the static OKD docs URL,
// regardless of OPERATOR_IMAGE_VERSION.
// The OCP code path is covered by TestFormatOCPDocURL and
// TestExtractMajorMinor in doc_url_test.go.
const expectedOKDDocURL = "https://docs.okd.io/latest/"

tests := []struct {
name string
operatorImageVersion string
}{
{name: "returns expected OKD documentation URL"},
{
name: "OPERATOR_IMAGE_VERSION does not affect OKD build",
operatorImageVersion: "5.0.3",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.operatorImageVersion != "" {
t.Setenv("OPERATOR_IMAGE_VERSION", tt.operatorImageVersion)
}
got := DefaultDocURL()
if got != expectedOKDDocURL {
t.Errorf("DefaultDocURL() = %q, want %q", got, expectedOKDDocURL)
}
})
}
}
137 changes: 137 additions & 0 deletions pkg/console/subresource/configmap/doc_url_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package configmap

import "testing"

func TestFormatOCPDocURL(t *testing.T) {
tests := []struct {
name string
version string
want string
}{
{
name: "full release version",
version: "5.0.3",
want: "https://access.redhat.com/documentation/en-us/openshift_container_platform/5.0/",
},
{
name: "two-part version",
version: "4.21",
want: "https://access.redhat.com/documentation/en-us/openshift_container_platform/4.21/",
},
{
name: "nightly pre-release version",
version: "5.1.0-0.nightly-2026-01-01-000000",
want: "https://access.redhat.com/documentation/en-us/openshift_container_platform/5.1/",
},
{
name: "rc version",
version: "4.19.0-rc.1",
want: "https://access.redhat.com/documentation/en-us/openshift_container_platform/4.19/",
},
{
name: "empty version falls back to latest",
version: "",
want: "https://access.redhat.com/documentation/en-us/openshift_container_platform/latest/",
},
{
name: "single number without dot falls back to latest",
version: "5",
want: "https://access.redhat.com/documentation/en-us/openshift_container_platform/latest/",
},
{
name: "non-numeric dotted version falls back to latest",
version: "invalid.version",
want: "https://access.redhat.com/documentation/en-us/openshift_container_platform/latest/",
},
{
name: "trailing dot falls back to latest",
version: "5.",
want: "https://access.redhat.com/documentation/en-us/openshift_container_platform/latest/",
},
{
name: "non-numeric minor falls back to latest",
version: "5.x",
want: "https://access.redhat.com/documentation/en-us/openshift_container_platform/latest/",
},
{
name: "leading dot falls back to latest",
version: ".5",
want: "https://access.redhat.com/documentation/en-us/openshift_container_platform/latest/",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := formatOCPDocURL(tt.version)
if got != tt.want {
t.Errorf("formatOCPDocURL(%q) = %q, want %q", tt.version, got, tt.want)
}
})
}
}

func TestExtractMajorMinor(t *testing.T) {
tests := []struct {
name string
version string
want string
}{
{
name: "standard three-part version",
version: "5.0.3",
want: "5.0",
},
{
name: "two-part version",
version: "4.21",
want: "4.21",
},
{
name: "nightly build version",
version: "5.1.0-0.nightly-2026-01-01-000000",
want: "5.1",
},
{
name: "release candidate",
version: "4.19.0-rc.1",
want: "4.19",
},
{
name: "empty string",
version: "",
want: "latest",
},
{
name: "single number without dot",
version: "5",
want: "latest",
},
{
name: "non-numeric dotted version",
version: "invalid.version",
want: "latest",
},
{
name: "trailing dot with empty minor",
version: "5.",
want: "latest",
},
{
name: "non-numeric minor component",
version: "5.x",
want: "latest",
},
{
name: "leading dot with empty major",
version: ".5",
want: "latest",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := extractMajorMinor(tt.version)
if got != tt.want {
t.Errorf("extractMajorMinor(%q) = %q, want %q", tt.version, got, tt.want)
}
})
}
}