Repository: JanDeDobbeleer/oh-my-posh (go)

Issue:
Dotnet segment enhancements
### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

### What would you like to see changed?

I have multiple repos that use different versions of .NET (reluctantly).
The current dotnet segment displays the latest one installed using `dotnet --version`. So that means when i'm on a project that uses an older .NET version, i'm displayed the incorrect version.

It would be great if we had the option to look for the version defined in [global.json](https://learn.microsoft.com/en-us/dotnet/core/tools/global-json) in the current folder/parent folder of the repo.

Pull request:
feat(dotnet): fetch SDK version in global.json
### 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

resolves #6363

<!---

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/segments/dotnet.go b/src/segments/dotnet.go
index 0f93abb0..7c38d347 100644
--- a/src/segments/dotnet.go
+++ b/src/segments/dotnet.go
@@ -1,12 +1,26 @@
 package segments
 
 import (
+	"encoding/json"
+
 	"github.com/jandedobbeleer/oh-my-posh/src/constants"
+	"github.com/jandedobbeleer/oh-my-posh/src/properties"
+)
+
+type globalJSON struct {
+	Sdk struct {
+		Version string `json:"version"`
+	} `json:"sdk"`
+}
+
+const (
+	// FetchSDKVersion fetches the SDK version in global.json
+	FetchSDKVersion properties.Property = "fetch_sdk_version"
 )
 
 type Dotnet struct {
+	SDKVersion string
 	language
-
 	Unsupported bool
 }
 
@@ -42,6 +56,24 @@ func (d *Dotnet) Enabled() bool {
 	if !enabled {
 		return false
 	}
+
 	d.Unsupported = d.exitCode == constants.DotnetExitCode
+
+	if !d.props.GetBool(FetchSDKVersion, false) {
+		return true
+	}
+
+	file, err := d.env.HasParentFilePath("global.json", false)
+	if err != nil {
+		return true
+	}
+
+	content := d.env.FileContent(file.Path)
+
+	var globalJSON globalJSON
+	if err := json.Unmarshal([]byte(content), &globalJSON); err == nil {
+		d.SDKVersion = globalJSON.Sdk.Version
+	}
+
 	return true
 }
diff --git a/website/docs/segments/languages/dotnet.mdx b/website/docs/segments/languages/dotnet.mdx
index b016c4ce..04825c0a 100644
--- a/website/docs/segments/languages/dotnet.mdx
+++ b/website/docs/segments/languages/dotnet.mdx
@@ -35,6 +35,7 @@ import Config from "@site/src/components/Config.js";
 | `version_url_template` |  `string`  |                                                                                            | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |
 | `extensions`           | `[]string` | `*.cs, *.csx, *.vb, *.fs, *.fsx, *.sln, *.slnf, *.csproj, *.fsproj, *.vbproj, global.json` | allows to override the default list of file extensions to validate                                                                                                                                                                   |
 | `folders`              | `[]string` |                                                                                            | allows to override the list of folder names to validate                                                                                                                                                                              |
+| `fetch_sdk_version`    | `boolean`  |                                          `false`                                           | fetch the SDK version in `global.json` when present                                                                                                                                                                                  |
 
 ## Template ([info][templates])
 
@@ -48,16 +49,17 @@ import Config from "@site/src/components/Config.js";
 
 ### Properties
 
-| Name             | Type     | Description                                        |
-| ---------------- | -------- | -------------------------------------------------- |
-| `.Full`          | `string` | the full version                                   |
-| `.Major`         | `string` | major number                                       |
-| `.Minor`         | `string` | minor number                                       |
-| `.Patch`         | `string` | patch number                                       |
-| `.Prerelease`    | `string` | prerelease info text                               |
-| `.BuildMetadata` | `string` | build metadata                                     |
-| `.URL`           | `string` | URL of the version info / release notes            |
-| `.Error`         | `string` | error encountered when fetching the version string |
+| Name             | Type     | Description                                                         |
+| ---------------- | -------- | ------------------------------------------------------------------- |
+| `.Full`          | `string` | the full version                                                    |
+| `.Major`         | `string` | major number                                                        |
+| `.Minor`         | `string` | minor number                                                        |
+| `.Patch`         | `string` | patch number                                                        |
+| `.Prerelease`    | `string` | prerelease info text                                                |
+| `.BuildMetadata` | `string` | build metadata                                                      |
+| `.URL`           | `string` | URL of the version info / release notes                             |
+| `.SDKVersion`    | `string` | the SDK version in `global.json` when `fetch_sdk_version` is `true` |
+| `.Error`         | `string` | error encountered when fetching the version string                  |
 
 [go-text-template]: https://golang.org/pkg/text/template/
 [templates]: /docs/configuration/templates


Test patch:
diff --git a/src/segments/dotnet_test.go b/src/segments/dotnet_test.go
index a81f9b4f..61355496 100644
--- a/src/segments/dotnet_test.go
+++ b/src/segments/dotnet_test.go
@@ -1,9 +1,11 @@
 package segments
 
 import (
+	"errors"
 	"testing"
 
 	"github.com/jandedobbeleer/oh-my-posh/src/constants"
+	"github.com/jandedobbeleer/oh-my-posh/src/properties"
 	"github.com/jandedobbeleer/oh-my-posh/src/runtime"
 
 	"github.com/stretchr/testify/assert"
@@ -42,3 +44,73 @@ func TestDotnetSegment(t *testing.T) {
 		assert.Equal(t, tc.Expected, renderTemplate(env, dotnet.Template(), dotnet), tc.Case)
 	}
 }
+
+func TestDotnetSDKVersion(t *testing.T) {
+	cases := []struct {
+		Case           string
+		GlobalJSON     string
+		ExpectedSDK    string
+		GlobalJSONPath string
+		FetchSDK       bool
+		HasGlobalJSON  bool
+	}{
+		{
+			Case:        "Do not fetch SDK version",
+			FetchSDK:    false,
+			ExpectedSDK: "",
+		},
+		{
+			Case:        "No global.json found",
+			FetchSDK:    true,
+			ExpectedSDK: "",
+		},
+		{
+			Case:           "Valid global.json",
+			FetchSDK:       true,
+			GlobalJSON:     `{"sdk": {"version": "6.0.100"}}`,
+			ExpectedSDK:    "6.0.100",
+			HasGlobalJSON:  true,
+			GlobalJSONPath: "/test/global.json",
+		},
+		{
+			Case:           "Invalid global.json",
+			FetchSDK:       true,
+			GlobalJSON:     `invalid json`,
+			ExpectedSDK:    "",
+			HasGlobalJSON:  true,
+			GlobalJSONPath: "/test/global.json",
+		},
+	}
+
+	params := &mockedLanguageParams{
+		cmd:           "dotnet",
+		versionParam:  "--version",
+		versionOutput: "6.0.100",
+		extension:     "*.cs",
+	}
+
+	for _, tc := range cases {
+		props := properties.Map{
+			FetchSDKVersion:         tc.FetchSDK,
+			properties.FetchVersion: false,
+		}
+
+		env, _ := getMockedLanguageEnv(params)
+
+		if tc.HasGlobalJSON {
+			file := &runtime.FileInfo{
+				Path: tc.GlobalJSONPath,
+			}
+			env.On("HasParentFilePath", "global.json", false).Return(file, nil)
+			env.On("FileContent", tc.GlobalJSONPath).Return(tc.GlobalJSON)
+		} else {
+			env.On("HasParentFilePath", "global.json", false).Return(&runtime.FileInfo{}, errors.New("file not found"))
+		}
+
+		dotnet := &Dotnet{}
+		dotnet.Init(props, env)
+
+		assert.True(t, dotnet.Enabled(), tc.Case)
+		assert.Equal(t, tc.ExpectedSDK, dotnet.SDKVersion, tc.Case)
+	}
+}