mirror of https://github.com/helm/helm
Merge pull request #31034 from Mazafard/feat/color-output-and-test-fixes
Feat: Add color output functionality and tests for release statusespull/31107/head
commit
18b7d45999
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
Copyright The Helm Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package output
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/fatih/color"
|
||||||
|
|
||||||
|
release "helm.sh/helm/v4/pkg/release/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ColorizeStatus returns a colorized version of the status string based on the status value
|
||||||
|
func ColorizeStatus(status release.Status, noColor bool) string {
|
||||||
|
// Disable color if requested
|
||||||
|
if noColor {
|
||||||
|
return status.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch status {
|
||||||
|
case release.StatusDeployed:
|
||||||
|
return color.GreenString(status.String())
|
||||||
|
case release.StatusFailed:
|
||||||
|
return color.RedString(status.String())
|
||||||
|
case release.StatusPendingInstall, release.StatusPendingUpgrade, release.StatusPendingRollback, release.StatusUninstalling:
|
||||||
|
return color.YellowString(status.String())
|
||||||
|
case release.StatusUnknown:
|
||||||
|
return color.RedString(status.String())
|
||||||
|
default:
|
||||||
|
// For uninstalled, superseded, and any other status
|
||||||
|
return status.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ColorizeHeader returns a colorized version of a header string
|
||||||
|
func ColorizeHeader(header string, noColor bool) string {
|
||||||
|
// Disable color if requested
|
||||||
|
if noColor {
|
||||||
|
return header
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use bold for headers
|
||||||
|
return color.New(color.Bold).Sprint(header)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ColorizeNamespace returns a colorized version of a namespace string
|
||||||
|
func ColorizeNamespace(namespace string, noColor bool) string {
|
||||||
|
// Disable color if requested
|
||||||
|
if noColor {
|
||||||
|
return namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use cyan for namespaces
|
||||||
|
return color.CyanString(namespace)
|
||||||
|
}
|
@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
Copyright The Helm Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package output
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
release "helm.sh/helm/v4/pkg/release/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestColorizeStatus(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
status release.Status
|
||||||
|
noColor bool
|
||||||
|
envNoColor string
|
||||||
|
wantColor bool // whether we expect color codes in output
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "deployed status with color",
|
||||||
|
status: release.StatusDeployed,
|
||||||
|
noColor: false,
|
||||||
|
envNoColor: "",
|
||||||
|
wantColor: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "deployed status without color flag",
|
||||||
|
status: release.StatusDeployed,
|
||||||
|
noColor: true,
|
||||||
|
envNoColor: "",
|
||||||
|
wantColor: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "deployed status with NO_COLOR env",
|
||||||
|
status: release.StatusDeployed,
|
||||||
|
noColor: false,
|
||||||
|
envNoColor: "1",
|
||||||
|
wantColor: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "failed status with color",
|
||||||
|
status: release.StatusFailed,
|
||||||
|
noColor: false,
|
||||||
|
envNoColor: "",
|
||||||
|
wantColor: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pending install status with color",
|
||||||
|
status: release.StatusPendingInstall,
|
||||||
|
noColor: false,
|
||||||
|
envNoColor: "",
|
||||||
|
wantColor: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unknown status with color",
|
||||||
|
status: release.StatusUnknown,
|
||||||
|
noColor: false,
|
||||||
|
envNoColor: "",
|
||||||
|
wantColor: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "superseded status with color",
|
||||||
|
status: release.StatusSuperseded,
|
||||||
|
noColor: false,
|
||||||
|
envNoColor: "",
|
||||||
|
wantColor: false, // superseded doesn't get colored
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Setenv("NO_COLOR", tt.envNoColor)
|
||||||
|
|
||||||
|
result := ColorizeStatus(tt.status, tt.noColor)
|
||||||
|
|
||||||
|
// Check if result contains ANSI escape codes
|
||||||
|
hasColor := strings.Contains(result, "\033[")
|
||||||
|
|
||||||
|
// In test environment, term.IsTerminal will be false, so we won't get color
|
||||||
|
// unless we're testing the logic without terminal detection
|
||||||
|
if hasColor && !tt.wantColor {
|
||||||
|
t.Errorf("ColorizeStatus() returned color when none expected: %q", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always check the status text is present
|
||||||
|
if !strings.Contains(result, tt.status.String()) {
|
||||||
|
t.Errorf("ColorizeStatus() = %q, want to contain %q", result, tt.status.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestColorizeHeader(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
header string
|
||||||
|
noColor bool
|
||||||
|
envNoColor string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "header with color",
|
||||||
|
header: "NAME",
|
||||||
|
noColor: false,
|
||||||
|
envNoColor: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "header without color flag",
|
||||||
|
header: "NAME",
|
||||||
|
noColor: true,
|
||||||
|
envNoColor: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "header with NO_COLOR env",
|
||||||
|
header: "NAME",
|
||||||
|
noColor: false,
|
||||||
|
envNoColor: "1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Setenv("NO_COLOR", tt.envNoColor)
|
||||||
|
|
||||||
|
result := ColorizeHeader(tt.header, tt.noColor)
|
||||||
|
|
||||||
|
// Always check the header text is present
|
||||||
|
if !strings.Contains(result, tt.header) {
|
||||||
|
t.Errorf("ColorizeHeader() = %q, want to contain %q", result, tt.header)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestColorizeNamespace(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
namespace string
|
||||||
|
noColor bool
|
||||||
|
envNoColor string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "namespace with color",
|
||||||
|
namespace: "default",
|
||||||
|
noColor: false,
|
||||||
|
envNoColor: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "namespace without color flag",
|
||||||
|
namespace: "default",
|
||||||
|
noColor: true,
|
||||||
|
envNoColor: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "namespace with NO_COLOR env",
|
||||||
|
namespace: "default",
|
||||||
|
noColor: false,
|
||||||
|
envNoColor: "1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Setenv("NO_COLOR", tt.envNoColor)
|
||||||
|
|
||||||
|
result := ColorizeNamespace(tt.namespace, tt.noColor)
|
||||||
|
|
||||||
|
// Always check the namespace text is present
|
||||||
|
if !strings.Contains(result, tt.namespace) {
|
||||||
|
t.Errorf("ColorizeNamespace() = %q, want to contain %q", result, tt.namespace)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue