Repository: JanDeDobbeleer/oh-my-posh
Pull request #4889 (2024-05-01 21:36:09)

Talosctl Segment
### Prerequisites

- [x] I have read and understood the [contributing guide][CONTRIBUTING.md].
- [x] The commit message follows the [conventional commits][cc] guidelines.
- [x] Tests for the changes have been added (for bug fixes / features).
- [x] Docs have been added/updated (for bug fixes / features).

### Description

Per https://github.com/JanDeDobbeleer/oh-my-posh/issues/4879, the Talosctl segment makes its debut.

### Work Done

As described in the above issue, `talosctl` creates a file in `.talos/config` that registers the current context. This context name (similar to the idea of `kubectl`) can now be displayed in a segment.

### Images

Example of `talosctl` segment working:

![Talosctl Working](https://github.com/JanDeDobbeleer/oh-my-posh/assets/56458442/f8b7b062-0e0b-4044-9f22-8f0b3196db92)

Inclusion of the segment within the `cloud-context` theme:

![cloud-context theme](https://github.com/JanDeDobbeleer/oh-my-posh/assets/56458442/7c218c83-51b4-46d9-b57a-b99ab030148d)

New documentation page:

![website doc](https://github.com/JanDeDobbeleer/oh-my-posh/assets/56458442/de882b74-3731-49fd-9b12-679e8fe4c019)


<!---

Tips:

If you're not comfortable with working with Git,
we're working a guide (https://ohmyposh.dev/docs/contributing_git) to help you out.
Oh My Posh advises GitKraken (https://www.gitkraken.com/invite/nQmDPR9D) as your preferred cross platform Git GUI power tool.

-->

[CONTRIBUTING.md]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/CONTRIBUTING.md
[cc]: https://www.conventionalcommits.org/en/v1.0.0/#summary



Patch:
diff --git a/src/engine/segment.go b/src/engine/segment.go
index 7be2413e..8c55a265 100644
--- a/src/engine/segment.go
+++ b/src/engine/segment.go
@@ -240,6 +240,8 @@ const (
 	SWIFT SegmentType = "swift"
 	// SYSTEMINFO writes system information (memory, cpu, load)
 	SYSTEMINFO SegmentType = "sysinfo"
+	// TALOSCTL writes the talosctl context
+	TALOSCTL SegmentType = "talosctl"
 	// TERRAFORM writes the terraform workspace we're currently in
 	TERRAFORM SegmentType = "terraform"
 	// TEXT writes a text
@@ -345,6 +347,7 @@ var Segments = map[SegmentType]func() SegmentWriter{
 	SVN:             func() SegmentWriter { return &segments.Svn{} },
 	SWIFT:           func() SegmentWriter { return &segments.Swift{} },
 	SYSTEMINFO:      func() SegmentWriter { return &segments.SystemInfo{} },
+	TALOSCTL:        func() SegmentWriter { return &segments.TalosCTL{} },
 	TERRAFORM:       func() SegmentWriter { return &segments.Terraform{} },
 	TEXT:            func() SegmentWriter { return &segments.Text{} },
 	TIME:            func() SegmentWriter { return &segments.Time{} },
diff --git a/src/segments/talosctl.go b/src/segments/talosctl.go
new file mode 100644
index 00000000..fe6d9fc5
--- /dev/null
+++ b/src/segments/talosctl.go
@@ -0,0 +1,56 @@
+package segments
+
+import (
+	"errors"
+	"path/filepath"
+
+	"github.com/jandedobbeleer/oh-my-posh/src/platform"
+	"github.com/jandedobbeleer/oh-my-posh/src/properties"
+	"gopkg.in/yaml.v3"
+)
+
+type TalosCTL struct {
+	props properties.Properties
+	env   platform.Environment
+
+	Context string `yaml:"context"`
+}
+
+func (t *TalosCTL) Template() string {
+	return " {{ .Context}} "
+}
+
+func (t *TalosCTL) Init(props properties.Properties, env platform.Environment) {
+	t.props = props
+	t.env = env
+}
+
+func (t *TalosCTL) Enabled() bool {
+	cfgDir := filepath.Join(t.env.Home(), ".talos")
+	configFile, err := t.getActiveConfig(cfgDir)
+	if err != nil {
+		t.env.Error(err)
+		return false
+	}
+
+	err = yaml.Unmarshal([]byte(configFile), t)
+	if err != nil {
+		t.env.Error(err)
+		return false
+	}
+
+	if len(t.Context) == 0 {
+		return false
+	}
+
+	return true
+}
+
+func (t *TalosCTL) getActiveConfig(cfgDir string) (string, error) {
+	activeConfigFile := filepath.Join(cfgDir, "config")
+	activeConfigData := t.env.FileContent(activeConfigFile)
+	if len(activeConfigData) == 0 {
+		return "", errors.New("NO ACTIVE CONFIG FOUND")
+	}
+	return activeConfigData, nil
+}
diff --git a/themes/cloud-context.omp.json b/themes/cloud-context.omp.json
index d2bf2627..61acfd4f 100644
--- a/themes/cloud-context.omp.json
+++ b/themes/cloud-context.omp.json
@@ -12,6 +12,7 @@
     "error-text": "#242424",
     "git-text": "#238636",
     "kubernetes-text": "#FFBB00",
+    "talosctl-text": "#FF6C00",
     "symbol-color": "#ffffff",
     "timer-text": "#dd0033"
   },
@@ -39,6 +40,14 @@
           "template": "<p:symbol-color>\uf308</> {{.Context}}{{if .Namespace}} \uf061 {{.Namespace}}{{end}}",
           "type": "kubectl"
         },
+        {
+          "background": "p:background-color",
+          "foreground": "p:talosctl-text",
+          "style": "powerline",
+          "powerline_symbol": "\ue0b4",
+          "template": "<p:symbol-color>\udb84\udcfe</> {{.Context}}",
+          "type": "talosctl"
+        },
         {
           "background": "p:background-color",
           "foreground": "p:cloud-text-amazon",
diff --git a/themes/schema.json b/themes/schema.json
index 0d0853f6..f9e249b3 100644
--- a/themes/schema.json
+++ b/themes/schema.json
@@ -360,6 +360,7 @@
             "strava",
             "svn",
             "swift",
+            "talosctl",
             "time",
             "text",
             "terraform",
@@ -2779,6 +2780,19 @@
             }
           }
         },
+        {
+          "if": {
+            "properties": {
+              "type": {
+                "const": "talosctl"
+              }
+            }
+          },
+          "then": {
+            "title": "Talosctl Segment",
+            "description": "https://ohmyposh.dev/docs/segments/talosctl"
+          }
+        },
         {
           "if": {
             "properties": {
diff --git a/website/docs/segments/talosctl.mdx b/website/docs/segments/talosctl.mdx
new file mode 100644
index 00000000..0c2f4bcc
--- /dev/null
+++ b/website/docs/segments/talosctl.mdx
@@ -0,0 +1,47 @@
+---
+id: talosctl
+title: Talosctl Context
+sidebar_label: Talosctl
+---
+
+## What
+
+Displays the currently active Talosctl context name.
+
+This segment leverages the `.talos/config` file generated by the [Talosctl CLI][talosctl].
+The CLI docs can be found by going to Documentation > Reference > CLI.
+For example, [v1.7 CLI][CLI].
+
+## Sample Configuration
+
+import Config from '@site/src/components/Config.js';
+
+<Config data={{
+  "type": "talosctl",
+  "style": "powerline",
+  "powerline_symbol": "\uE0B0",
+  "foreground": "#FFFFFF",
+  "background": "#FF6C00",
+  "template": " \udb84\udcfe {{ .Context }}"
+}}/>
+
+## Template ([info][templates])
+
+:::note default template
+
+```template
+{{ .Context }}
+```
+
+:::
+
+### Properties
+
+| Name         | Type     | Description                           |
+| ------------ | -------- | ------------------------------------- |
+| `.Context`   | `string` | the current talosctl context           |
+
+
+[templates]: /docs/configuration/templates
+[talosctl]: https://www.talos.dev/
+[CLI]: https://www.talos.dev/v1.7/reference/cli/
diff --git a/website/sidebars.js b/website/sidebars.js
index 51ea96e6..870214be 100644
--- a/website/sidebars.js
+++ b/website/sidebars.js
@@ -123,6 +123,7 @@ module.exports = {
         "segments/svn",
         "segments/swift",
         "segments/sysinfo",
+        "segments/talosctl",
         "segments/terraform",
         "segments/text",
         "segments/time",


Test patch:
diff --git a/src/segments/talosctl_test.go b/src/segments/talosctl_test.go
new file mode 100644
index 00000000..5c565835
--- /dev/null
+++ b/src/segments/talosctl_test.go
@@ -0,0 +1,95 @@
+package segments
+
+import (
+	"path/filepath"
+	"testing"
+
+	"github.com/jandedobbeleer/oh-my-posh/src/mock"
+	"github.com/stretchr/testify/assert"
+	mock2 "github.com/stretchr/testify/mock"
+)
+
+func TestTalosctlSegment(t *testing.T) {
+	cases := []struct {
+		Case            string
+		ActiveConfig    string
+		ExpectedEnabled bool
+		ExpectedString  string
+	}{
+		{
+			Case:            "happy path",
+			ExpectedEnabled: true,
+			ActiveConfig:    "context: context-name",
+			ExpectedString:  "context-name",
+		},
+		{
+			Case:            "no active config",
+			ExpectedEnabled: false,
+		},
+		{
+			Case:            "empty config",
+			ActiveConfig:    "",
+			ExpectedEnabled: false,
+		},
+		{
+			Case:            "bad config",
+			ActiveConfig:    "other-yaml: not-expected",
+			ExpectedEnabled: false,
+		},
+	}
+
+	for _, tc := range cases {
+		env := new(mock.MockedEnvironment)
+		env.On("Home").Return("home")
+		fcPath := filepath.Join("home", ".talos", "config")
+		env.On("FileContent", fcPath).Return(tc.ActiveConfig)
+		env.On("Error", mock2.Anything).Return()
+		talos := TalosCTL{
+			env: env,
+		}
+		talos.Enabled()
+		assert.Equal(t, tc.ExpectedEnabled, talos.Enabled())
+		if tc.ExpectedEnabled {
+			assert.Equal(t, tc.ExpectedString, renderTemplate(env, talos.Template(), talos), tc.Case)
+		}
+	}
+}
+
+func TestGetTalosctlActiveConfig(t *testing.T) {
+	cases := []struct {
+		Case           string
+		ActiveConfig   string
+		ExpectedString string
+		ExpectedError  string
+	}{
+		{
+			Case:           "happy path",
+			ActiveConfig:   "context: context-name",
+			ExpectedString: "context: context-name",
+		},
+		{
+			Case:          "no active config",
+			ActiveConfig:  "",
+			ExpectedError: "NO ACTIVE CONFIG FOUND",
+		},
+	}
+
+	for _, tc := range cases {
+		env := new(mock.MockedEnvironment)
+		env.On("Home").Return("home")
+		configPath := filepath.Join("home", ".talos")
+		contentPath := filepath.Join(configPath, "config")
+		env.On("FileContent", contentPath).Return(tc.ActiveConfig)
+		env.On("Error", mock2.Anything).Return()
+		talos := TalosCTL{
+			env: env,
+		}
+		got, err := talos.getActiveConfig(configPath)
+		assert.Equal(t, tc.ExpectedString, got, tc.Case)
+		if len(tc.ExpectedError) > 0 {
+			assert.EqualError(t, err, tc.ExpectedError, tc.Case)
+		} else {
+			assert.NoError(t, err, tc.Case)
+		}
+	}
+}