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.
This commit is contained in:
lnu 2021-01-10 12:14:43 +01:00 committed by Jan De Dobbeleer
parent 7a4d2e175b
commit 59c81f3a9f
7 changed files with 164 additions and 19 deletions

View file

@ -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<version>[0-9]+.[0-9]+.[0-9]+)`,
version: &version{
regex: `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?:\d{2})(?P<patch>[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)",
},
}
}

View file

@ -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<version>[0-9]+.[0-9]+.[0-9]+)`,
version: &version{
regex: `(?:go(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,
urlTemplate: "[%s](https://golang.org/doc/go%s.%s)",
},
}
}

View file

@ -15,7 +15,9 @@ func (j *julia) init(props *properties, env environmentInfo) {
commands: []string{"julia"},
versionParam: "--version",
extensions: []string{"*.jl"},
versionRegex: `julia version (?P<version>[0-9]+.[0-9]+.[0-9]+)`,
version: &version{
regex: `julia version (?P<version>[0-9]+.[0-9]+.[0-9]+)`,
},
}
}

View file

@ -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
}

View file

@ -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<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[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<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[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<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[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())
}

View file

@ -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<version>[0-9]+.[0-9]+.[0-9]+)`,
version: &version{
regex: `(?:v(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,
urlTemplate: "[%[1]s](https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V%[2]s.md#%[1]s)",
},
}
}

View file

@ -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<version>[0-9]+.[0-9]+.[0-9]+)`,
loadContext: p.loadContext,
inContext: p.inContext,
version: &version{
regex: `(?:Python (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,
urlTemplate: "[%s](https://www.python.org/downloads/release/python-%s%s%s/)",
},
}
}