From 59c81f3a9f7564957e6c62e0063cabf4933a325e Mon Sep 17 00:00:00 2001 From: lnu Date: Sun, 10 Jan 2021 12:14:43 +0100 Subject: [PATCH] feat: release notes hyperlink for all languages If version enabled and hyperlink enabled(global level), an hyperlink to the release notes of the current version is generated. The regex and the url template can be modified in the json template. --- src/segment_dotnet.go | 5 ++- src/segment_golang.go | 5 ++- src/segment_julia.go | 4 +- src/segment_language.go | 73 +++++++++++++++++++++++++----- src/segment_language_test.go | 86 ++++++++++++++++++++++++++++++++++-- src/segment_node.go | 5 ++- src/segment_python.go | 5 ++- 7 files changed, 164 insertions(+), 19 deletions(-) diff --git a/src/segment_dotnet.go b/src/segment_dotnet.go index 765a6629..3fea937f 100644 --- a/src/segment_dotnet.go +++ b/src/segment_dotnet.go @@ -30,7 +30,10 @@ func (d *dotnet) init(props *properties, env environmentInfo) { commands: []string{"dotnet"}, versionParam: "--version", extensions: []string{"*.cs", "*.vb", "*.sln", "*.csproj", "*.vbproj"}, - versionRegex: `(?P[0-9]+.[0-9]+.[0-9]+)`, + version: &version{ + regex: `(?:(?P((?P[0-9]+).(?P[0-9]+).(?:\d{2})(?P[0-9]{1}))))`, + urlTemplate: "[%1s](https://github.com/dotnet/core/blob/master/release-notes/%[2]s.%[3]s/%[2]s.%[3]s.%[4]s/%[2]s.%[3]s.%[4]s.md)", + }, } } diff --git a/src/segment_golang.go b/src/segment_golang.go index 82578a32..ade18c2d 100644 --- a/src/segment_golang.go +++ b/src/segment_golang.go @@ -15,7 +15,10 @@ func (g *golang) init(props *properties, env environmentInfo) { commands: []string{"go"}, versionParam: "version", extensions: []string{"*.go", "go.mod"}, - versionRegex: `go(?P[0-9]+.[0-9]+.[0-9]+)`, + version: &version{ + regex: `(?:go(?P((?P[0-9]+).(?P[0-9]+).(?P[0-9]+))))`, + urlTemplate: "[%s](https://golang.org/doc/go%s.%s)", + }, } } diff --git a/src/segment_julia.go b/src/segment_julia.go index e2cabeb2..26141028 100644 --- a/src/segment_julia.go +++ b/src/segment_julia.go @@ -15,7 +15,9 @@ func (j *julia) init(props *properties, env environmentInfo) { commands: []string{"julia"}, versionParam: "--version", extensions: []string{"*.jl"}, - versionRegex: `julia version (?P[0-9]+.[0-9]+.[0-9]+)`, + version: &version{ + regex: `julia version (?P[0-9]+.[0-9]+.[0-9]+)`, + }, } } diff --git a/src/segment_language.go b/src/segment_language.go index 2a2294a4..c94cf8ac 100644 --- a/src/segment_language.go +++ b/src/segment_language.go @@ -1,9 +1,37 @@ package main +import ( + "errors" + "fmt" + "strings" +) + type loadContext func() type inContext func() bool +type version struct { + full string + major string + minor string + patch string + regex string + urlTemplate string +} + +func (v *version) parse(versionInfo string) error { + values := findNamedRegexMatch(v.regex, versionInfo) + if len(values) == 0 { + return errors.New("cannot parse version string") + } + + v.full = values["version"] + v.major = values["major"] + v.minor = values["minor"] + v.patch = values["patch"] + return nil +} + type language struct { props *properties env environmentInfo @@ -11,8 +39,7 @@ type language struct { commands []string executable string versionParam string - versionRegex string - version string + version *version exitCode int loadContext loadContext inContext inContext @@ -42,8 +69,21 @@ func (l *language) string() string { if !l.hasCommand() { return l.props.getString(MissingCommandTextProperty, MissingCommandText) } - l.setVersion() - return l.version + + err := l.setVersion() + if err != nil { + return "" + } + + // build release notes hyperlink + if l.props.getBool(EnableHyperlink, false) && l.version.urlTemplate != "" { + version, err := TruncatingSprintf(l.version.urlTemplate, l.version.full, l.version.major, l.version.minor, l.version.patch) + if err != nil { + return l.version.full + } + return version + } + return l.version.full } func (l *language) enabled() bool { @@ -77,16 +117,18 @@ func (l *language) hasLanguageFiles() bool { return true } -// getVersion returns the version and exit code returned by the executable -func (l *language) setVersion() { +// setVersion parses the version string returned by the command +func (l *language) setVersion() error { versionInfo, err := l.env.runCommand(l.executable, l.versionParam) if exitErr, ok := err.(*commandError); ok { l.exitCode = exitErr.exitCode - return + return errors.New("error executing command") } - values := findNamedRegexMatch(l.versionRegex, versionInfo) - l.exitCode = 0 - l.version = values["version"] + err = l.version.parse(versionInfo) + if err != nil { + return err + } + return nil } // hasCommand checks if one of the commands exists and sets it as executable @@ -116,3 +158,14 @@ func (l *language) inLanguageContext() bool { } return l.inContext() } + +func TruncatingSprintf(str string, args ...interface{}) (string, error) { + n := strings.Count(str, "%s") + if n > len(args) { + return "", errors.New("Too many parameters") + } + if n == 0 { + return fmt.Sprintf(str, args...), nil + } + return fmt.Sprintf(str, args[:n]...), nil +} diff --git a/src/segment_language_test.go b/src/segment_language_test.go index 363a77b2..7c57b86f 100644 --- a/src/segment_language_test.go +++ b/src/segment_language_test.go @@ -7,7 +7,7 @@ import ( ) const ( - universion = "1.3.3.7" + universion = "1.3.307" uni = "*.uni" corn = "*.corn" ) @@ -23,6 +23,8 @@ type languageArgs struct { versionParam string versionRegex string missingCommandText string + urlTemplate string + enableHyperlink bool } func (l *languageArgs) hasvalue(value string, list []string) bool { @@ -45,8 +47,9 @@ func bootStrapLanguageTest(args *languageArgs) *language { } props := &properties{ values: map[Property]interface{}{ - DisplayVersion: args.displayVersion, - DisplayMode: args.displayMode, + DisplayVersion: args.displayVersion, + DisplayMode: args.displayMode, + EnableHyperlink: args.enableHyperlink, }, } if args.missingCommandText != "" { @@ -58,7 +61,10 @@ func bootStrapLanguageTest(args *languageArgs) *language { extensions: args.extensions, commands: args.commands, versionParam: args.versionParam, - versionRegex: args.versionRegex, + version: &version{ + regex: args.versionRegex, + urlTemplate: args.urlTemplate, + }, } return l } @@ -222,3 +228,75 @@ func TestLanguageEnabledMissingCommandCustomText(t *testing.T) { assert.True(t, lang.enabled()) assert.Equal(t, args.missingCommandText, lang.string(), "unicorn is available and uni and corn files are found") } + +func TestLanguageHyperlinkEnabled(t *testing.T) { + args := &languageArgs{ + versionParam: "--version", + commands: []string{"uni", "corn"}, + enabledCommands: []string{"corn"}, + extensions: []string{uni, corn}, + versionRegex: `(?P((?P[0-9]+).(?P[0-9]+).(?P[0-9]+)))`, + urlTemplate: "[%s](https://unicor.org/doc/%s.%s.%s)", + version: universion, + enabledExtensions: []string{corn}, + displayVersion: true, + enableHyperlink: true, + } + lang := bootStrapLanguageTest(args) + assert.True(t, lang.enabled()) + assert.Equal(t, "[1.3.307](https://unicor.org/doc/1.3.307)", lang.string()) +} + +func TestLanguageHyperlinkEnabledWrongRegex(t *testing.T) { + args := &languageArgs{ + versionParam: "--version", + commands: []string{"uni", "corn"}, + enabledCommands: []string{"corn"}, + extensions: []string{uni, corn}, + versionRegex: `wrong`, + urlTemplate: "[%s](https://unicor.org/doc/%s.%s.%s)", + version: universion, + enabledExtensions: []string{corn}, + displayVersion: true, + enableHyperlink: true, + } + lang := bootStrapLanguageTest(args) + assert.True(t, lang.enabled()) + assert.Equal(t, "", lang.string()) +} + +func TestLanguageHyperlinkEnabledLessParamInTemplate(t *testing.T) { + args := &languageArgs{ + versionParam: "--version", + commands: []string{"uni", "corn"}, + enabledCommands: []string{"corn"}, + extensions: []string{uni, corn}, + versionRegex: `(?P((?P[0-9]+).(?P[0-9]+).(?P[0-9]+)))`, + urlTemplate: "[%s](https://unicor.org/doc/%s)", + version: universion, + enabledExtensions: []string{corn}, + displayVersion: true, + enableHyperlink: true, + } + lang := bootStrapLanguageTest(args) + assert.True(t, lang.enabled()) + assert.Equal(t, "[1.3.307](https://unicor.org/doc/1)", lang.string()) +} + +func TestLanguageHyperlinkEnabledMoreParamInTemplate(t *testing.T) { + args := &languageArgs{ + versionParam: "--version", + commands: []string{"uni", "corn"}, + enabledCommands: []string{"corn"}, + extensions: []string{uni, corn}, + versionRegex: `(?P((?P[0-9]+).(?P[0-9]+).(?P[0-9]+)))`, + urlTemplate: "[%s](https://unicor.org/doc/%s.%s.%s.%s)", + version: universion, + enabledExtensions: []string{corn}, + displayVersion: true, + enableHyperlink: true, + } + lang := bootStrapLanguageTest(args) + assert.True(t, lang.enabled()) + assert.Equal(t, "1.3.307", lang.string()) +} diff --git a/src/segment_node.go b/src/segment_node.go index 6c8cb887..bd8ad888 100644 --- a/src/segment_node.go +++ b/src/segment_node.go @@ -15,7 +15,10 @@ func (n *node) init(props *properties, env environmentInfo) { commands: []string{"node"}, versionParam: "--version", extensions: []string{"*.js", "*.ts", "package.json"}, - versionRegex: `(?P[0-9]+.[0-9]+.[0-9]+)`, + version: &version{ + regex: `(?:v(?P((?P[0-9]+).(?P[0-9]+).(?P[0-9]+))))`, + urlTemplate: "[%[1]s](https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V%[2]s.md#%[1]s)", + }, } } diff --git a/src/segment_python.go b/src/segment_python.go index de2d932e..5a162d42 100644 --- a/src/segment_python.go +++ b/src/segment_python.go @@ -32,9 +32,12 @@ func (p *python) init(props *properties, env environmentInfo) { commands: []string{"python", "python3"}, versionParam: "--version", extensions: []string{"*.py", "*.ipynb", "pyproject.toml", "venv.bak", "venv", ".venv"}, - versionRegex: `Python (?P[0-9]+.[0-9]+.[0-9]+)`, loadContext: p.loadContext, inContext: p.inContext, + version: &version{ + regex: `(?:Python (?P((?P[0-9]+).(?P[0-9]+).(?P[0-9]+))))`, + urlTemplate: "[%s](https://www.python.org/downloads/release/python-%s%s%s/)", + }, } }