feat: UI5 tooling segment

This commit is contained in:
Jacek W 2022-02-14 08:41:33 +01:00 committed by GitHub
parent 91ebe662bf
commit b47e057f14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 335 additions and 1 deletions

View file

@ -0,0 +1,61 @@
---
id: ui5tooling
title: UI5 Tooling
sidebar_label: UI5 Tooling
---
## What
Display the active [UI5 tooling][ui5-homepage] version (global or local if present -
see [the documentation][ui5-version-help]).
## Sample Configuration
```json
{
"background": "#f5a834",
"foreground": "#100e23",
"powerline_symbol": "\ue0b0",
"properties": {
"template": " \ufab6ui5 {{ .Full }} "
},
"style": "powerline",
"type": "ui5tooling"
}
```
## Properties
- home_enabled: `boolean` - display the segment in the HOME folder or not - defaults to `false`
- fetch_version: `boolean` - display the UI5 tooling version - defaults to `true`
- display_error: `boolean` - show the error context when failing to retrieve the version information - defaults to `true`
- missing_command_text: `string` - text to display when the java command is missing - defaults to empty
- display_mode: `string` - determines when the segment is displayed
- `always`: the segment is always displayed
- `files`: the segment is only displayed when `*ui5*.y(a)ml` file is present in the current folder
- `context`: (default) the segment is only displayed when `*ui5*.y(a)ml` file is present in the current folder
or it has been found in the parent folders (check up to 4 levels)
## Template ([info][templates])
:::note default template
```template
{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}
```
:::
## Template Properties
- `.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
- `.Error`: `string` - when fetching the version string errors
[templates]: /docs/config-templates
[ui5-homepage]: https://sap.github.io/ui5-tooling
[ui5-version-help]: https://sap.github.io/ui5-tooling/pages/CLI/#ui5-versions

View file

@ -76,6 +76,7 @@ module.exports = {
"terraform", "terraform",
"text", "text",
"time", "time",
"ui5tooling",
"wakatime", "wakatime",
"wifi", "wifi",
"winreg", "winreg",

View file

@ -149,6 +149,8 @@ const (
IPIFY SegmentType = "ipify" IPIFY SegmentType = "ipify"
// HASKELL segment // HASKELL segment
HASKELL SegmentType = "haskell" HASKELL SegmentType = "haskell"
// UI5 Tooling segment
UI5TOOLING SegmentType = "ui5tooling"
) )
func (segment *Segment) shouldIncludeFolder() bool { func (segment *Segment) shouldIncludeFolder() bool {
@ -266,6 +268,7 @@ func (segment *Segment) mapSegmentWithWriter(env environment.Environment) error
BREWFATHER: &segments.Brewfather{}, BREWFATHER: &segments.Brewfather{},
IPIFY: &segments.IPify{}, IPIFY: &segments.IPify{},
HASKELL: &segments.Haskell{}, HASKELL: &segments.Haskell{},
UI5TOOLING: &segments.UI5Tooling{},
} }
if segment.Properties == nil { if segment.Properties == nil {
segment.Properties = make(properties.Map) segment.Properties = make(properties.Map)

View file

@ -150,6 +150,7 @@ type Environment interface {
HasFilesInDir(dir, pattern string) bool HasFilesInDir(dir, pattern string) bool
HasFolder(folder string) bool HasFolder(folder string) bool
HasParentFilePath(path string) (fileInfo *FileInfo, err error) HasParentFilePath(path string) (fileInfo *FileInfo, err error)
HasFileInParentDirs(pattern string, depth uint) bool
HasCommand(command string) bool HasCommand(command string) bool
FileContent(file string) string FileContent(file string) string
FolderList(path string) []string FolderList(path string) []string
@ -319,6 +320,25 @@ func (env *ShellEnvironment) HasFilesInDir(dir, pattern string) bool {
return len(matches) > 0 return len(matches) > 0
} }
func (env *ShellEnvironment) HasFileInParentDirs(pattern string, depth uint) bool {
defer env.trace(time.Now(), "HasFileInParent", pattern, fmt.Sprint(depth))
currentFolder := env.Pwd()
for c := 0; c < int(depth); c++ {
if env.HasFilesInDir(currentFolder, pattern) {
return true
}
if dir := filepath.Dir(currentFolder); dir != currentFolder {
currentFolder = dir
} else {
return false
}
}
return false
}
func (env *ShellEnvironment) HasFolder(folder string) bool { func (env *ShellEnvironment) HasFolder(folder string) bool {
defer env.trace(time.Now(), "HasFolder", folder) defer env.trace(time.Now(), "HasFolder", folder)
_, err := os.Stat(folder) _, err := os.Stat(folder)

View file

@ -209,3 +209,8 @@ func (env *MockedEnvironment) MockGitCommand(dir, returnValue string, args ...st
args = append([]string{"-C", dir, "--no-optional-locks", "-c", "core.quotepath=false", "-c", "color.status=false"}, args...) args = append([]string{"-C", dir, "--no-optional-locks", "-c", "core.quotepath=false", "-c", "color.status=false"}, args...)
env.On("RunCommand", "git", args).Return(returnValue, nil) env.On("RunCommand", "git", args).Return(returnValue, nil)
} }
func (env *MockedEnvironment) HasFileInParentDirs(pattern string, depth uint) bool {
args := env.Called(pattern, depth)
return args.Bool(0)
}

View file

@ -0,0 +1,49 @@
package segments
import (
"oh-my-posh/environment"
"oh-my-posh/properties"
)
const UI5ToolingYamlPattern = "*ui5*.y*ml"
type UI5Tooling struct {
language
HasUI5YamlInParentDir bool
}
func (u *UI5Tooling) Template() string {
return languageTemplate
}
func (u *UI5Tooling) Init(props properties.Properties, env environment.Environment) {
u.language = language{
env: env,
props: props,
extensions: []string{UI5ToolingYamlPattern},
loadContext: u.loadContext,
inContext: u.inContext,
displayMode: props.GetString(DisplayMode, DisplayModeContext),
commands: []*cmd{
{
executable: "ui5",
args: []string{"--version"},
regex: `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,
},
},
versionURLTemplate: "https://github.com/SAP/ui5-cli/releases/tag/v{{ .Full }}",
}
}
func (u *UI5Tooling) Enabled() bool {
return u.language.Enabled()
}
func (u *UI5Tooling) loadContext() {
// for searching ui5 yaml from subdirectories of UI5 project root - up to 4 levels
u.HasUI5YamlInParentDir = u.env.HasFileInParentDirs(UI5ToolingYamlPattern, 4)
}
func (u *UI5Tooling) inContext() bool {
return u.HasUI5YamlInParentDir
}

View file

@ -0,0 +1,168 @@
package segments
import (
"fmt"
"oh-my-posh/environment"
"oh-my-posh/mock"
"oh-my-posh/properties"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
const (
WorkingDirRoot = "/home/user/dev/my-app"
)
type testCase struct {
Case string
Template string
ExpectedString string
ExpectedEnabled bool
UI5YamlFilename string
WorkingDir string
Version string
DisplayMode string
}
func TestUI5Tooling(t *testing.T) {
cases := []testCase{
{
Case: "1) ui5tooling 2.12.1 - file ui5.yaml present in cwd; DisplayMode = files",
ExpectedString: "2.12.1",
ExpectedEnabled: true,
UI5YamlFilename: "ui5.yaml",
Version: `2.12.1 (from C:\somewhere\cli\bin\ui5.js)`,
DisplayMode: DisplayModeFiles,
},
{
Case: "2) ui5tooling 2.12.2 - file ui5.yaml present in cwd; default display mode (context)",
ExpectedString: "2.12.2",
ExpectedEnabled: true,
UI5YamlFilename: "ui5.yaml",
Version: `2.12.2 (from C:\somewhere\cli\bin\ui5.js)`,
},
{
Case: "3) ui5tooling 2.12.3 - file ui5.yaml present; cwd is sub dir, default display mode (context)",
ExpectedString: "2.12.3",
WorkingDir: WorkingDirRoot + "/subdir",
ExpectedEnabled: true,
UI5YamlFilename: "ui5.yaml",
Version: `2.12.3 (from C:\somewhere\cli\bin\ui5.js)`,
},
{
Case: "4) no ui5tooling segment - file ui5.yaml present, cwd is sub dir; display mode = files",
ExpectedString: "",
WorkingDir: WorkingDirRoot + "/subdir",
ExpectedEnabled: false,
UI5YamlFilename: "ui5.yaml",
DisplayMode: DisplayModeFiles,
Version: `2.12.1 (from C:\somewhere\cli\bin\ui5.js)`,
},
{
Case: "5) ui5tooling 2.12.4 - file ui5-dist.yml present in cwd",
ExpectedString: "2.12.4",
ExpectedEnabled: true,
UI5YamlFilename: "ui5-dist.yml",
Version: `2.12.4 (from C:\somewhere\cli\bin\ui5.js)`,
DisplayMode: DisplayModeFiles,
},
{
Case: "6) no ui5tooling segment - file ui5.yaml not present, display mode = files",
ExpectedString: "",
ExpectedEnabled: false,
Version: `2.12.1 (from C:\somewhere\cli\bin\ui5.js)`,
DisplayMode: DisplayModeFiles,
},
{
Case: "7) no ui5tooling segment - file ui5.yaml not present, default display mode (context)",
ExpectedString: "",
ExpectedEnabled: false,
Version: `2.12.1 (from C:\somewhere\cli\bin\ui5.js)`,
},
{
Case: "8) ui5tooling 11.0.0-rc1, no ui5.yaml file but display mode = always",
Template: "{{ .Major }}",
ExpectedString: "11",
ExpectedEnabled: true,
Version: `11.0.0-rc1 (from C:\somewhere\cli\bin\ui5.js)`,
DisplayMode: DisplayModeAlways,
},
}
for _, tc := range cases {
env := prepareMockedEnvironment(&tc)
ui5tooling := &UI5Tooling{}
if tc.WorkingDir == "" {
tc.WorkingDir = WorkingDirRoot
}
if tc.DisplayMode == "" {
tc.DisplayMode = DisplayModeContext
}
if tc.Template == "" {
tc.Template = ui5tooling.Template()
}
props := properties.Map{
DisplayMode: tc.DisplayMode,
}
ui5tooling.Init(props, env)
err := mockFilePresence(&tc, ui5tooling, env)
if err != nil {
t.Fail()
}
failMsg := fmt.Sprintf("Failed in case: %s", tc.Case)
assert.Equal(t, tc.ExpectedEnabled, ui5tooling.Enabled(), failMsg)
assert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, ui5tooling), failMsg)
}
}
func prepareMockedEnvironment(tc *testCase) *mock.MockedEnvironment {
var env = new(mock.MockedEnvironment)
env.On("HasCommand", "ui5").Return(true)
env.On("RunCommand", "ui5", []string{"--version"}).Return(tc.Version, nil)
env.On("Home").Return("/home/user")
env.On("Pwd").Return(WorkingDirRoot)
env.On("TemplateCache").Return(&environment.TemplateCache{
Env: make(map[string]string),
})
return env
}
func mockFilePresence(tc *testCase, ui5tooling *UI5Tooling, env *mock.MockedEnvironment) error {
for _, f := range ui5tooling.language.extensions {
match, err := filepath.Match(f, tc.UI5YamlFilename)
if err != nil {
return err
}
if match {
if tc.DisplayMode == DisplayModeFiles && tc.WorkingDir == WorkingDirRoot {
env.On("HasFiles", f).Return(true)
env.On("HasFileInParentDirs", f, uint(4)).Return(false)
// mode context, working dir != working dir root
} else if tc.DisplayMode == DisplayModeContext {
env.On("HasFileInParentDirs", f, uint(4)).Return(false)
env.On("HasFiles", f).Return(true)
} else {
env.On("HasFileInParentDirs", f, uint(4)).Return(false)
env.On("HasFiles", f).Return(false)
}
} else {
env.On("HasFileInParentDirs", f, uint(4)).Return(false)
env.On("HasFiles", f).Return(false)
}
}
return nil
}

View file

@ -183,7 +183,8 @@
"winreg", "winreg",
"plastic", "plastic",
"ipify", "ipify",
"haskell" "haskell",
"ui5tooling"
] ]
}, },
"style": { "style": {
@ -1907,6 +1908,32 @@
} }
} }
} }
},
{
"if": {
"properties": {
"type": { "const": "ui5tooling" }
}
},
"then": {
"title": "UI5 tooling CLI segment",
"description": "https://ohmyposh.dev/docs/ui5tooling",
"properties": {
"properties": {
"properties": {
"fetch_version": {
"$ref": "#/definitions/fetch_version"
},
"display_mode": {
"$ref": "#/definitions/display_mode"
},
"missing_command_text": {
"$ref": "#/definitions/missing_command_text"
}
}
}
}
}
} }
] ]
} }