diff --git a/docs-src/content/functions/semver.yml b/docs-src/content/functions/semver.yml new file mode 100644 index 000000000..08710afa1 --- /dev/null +++ b/docs-src/content/functions/semver.yml @@ -0,0 +1,49 @@ +ns: semver +preamble: | + These functions allow user you to parse a [semantic version](http://semver.org/) string or test it with constraint. + + It's implemented with the https://github.com/Masterminds/semver library. +funcs: + - name: semver.Semver + description: | + Returns a semantic version struct holding the `input` version string. + + The returned struct are defined at: [`semver.Version`](https://pkg.go.dev/github.com/Masterminds/semver/v3#Version). + pipeline: true + arguments: + - name: input + required: true + description: The input to parse + examples: + - | + $ gomplate -i '{{ semver.Semver "v1.1.1"}}' + 1.1.1 + - | + $ gomplate -i '{{ (semver.Semver "v1.1.1").Major }}' + 1 + - | + $ gomplate -i 'the pre release version is {{ ("v1.1.1" | semver.Semver).SetPrerelease "beta.1" }}' + the pre release version is 1.1.1-beta.1 + - name: semver.CheckConstraint + description: | + Test whether the input version matchs the constraint. + + Ref: https://github.com/Masterminds/semver#checking-version-constraints + pipeline: true + arguments: + - name: constraint + required: true + description: The constraints expression to test. + - name: input + required: true + description: The input semantic version string to test. + examples: + - | + $ gomplate -i '{{ semver.CheckConstraint "> 1.0" "v1.1.1" }}' + true + - | + $ gomplate -i '{{ semver.CheckConstraint "> 1.0, <1.1" "v1.1.1" }}' + false + - | + $ gomplate -i '{{ "v1.1.1" | semver.CheckConstraint "> 1.0" }}' + true diff --git a/docs/content/functions/semver.md b/docs/content/functions/semver.md new file mode 100644 index 000000000..b94488ff1 --- /dev/null +++ b/docs/content/functions/semver.md @@ -0,0 +1,85 @@ +--- +title: semver functions +menu: + main: + parent: functions +--- + +These functions allow user you to parse a [semantic version](http://semver.org/) string or test it with constraint. + +It's implemented with the https://github.com/Masterminds/semver library. + +## `semver.Semver`_(unreleased)_ +**Unreleased:** _This function is in development, and not yet available in released builds of gomplate._ + +Returns a semantic version struct holding the `input` version string. + +The returned struct are defined at: [`semver.Version`](https://pkg.go.dev/github.com/Masterminds/semver/v3#Version). + +### Usage + +``` +semver.Semver input +``` +``` +input | semver.Semver +``` + +### Arguments + +| name | description | +|------|-------------| +| `input` | _(required)_ The input to parse | + +### Examples + +```console +$ gomplate -i '{{ semver.Semver "v1.1.1"}}' +1.1.1 +``` +```console +$ gomplate -i '{{ (semver.Semver "v1.1.1").Major }}' +1 +``` +```console +$ gomplate -i 'the pre release version is {{ ("v1.1.1" | semver.Semver).SetPrerelease "beta.1" }}' +the pre release version is 1.1.1-beta.1 +``` + +## `semver.CheckConstraint`_(unreleased)_ +**Unreleased:** _This function is in development, and not yet available in released builds of gomplate._ + +Test whether the input version matchs the constraint. + +Ref: https://github.com/Masterminds/semver#checking-version-constraints + +### Usage + +``` +semver.CheckConstraint constraint input +``` +``` +input | semver.CheckConstraint constraint +``` + +### Arguments + +| name | description | +|------|-------------| +| `constraint` | _(required)_ The constraints expression to test. | +| `input` | _(required)_ The input semantic version string to test. | + +### Examples + +```console +$ gomplate -i '{{ semver.CheckConstraint "> 1.0" "v1.1.1" }}' +true +``` +```console +$ gomplate -i '{{ semver.CheckConstraint "> 1.0, <1.1" "v1.1.1" }}' +false +``` +```console +$ gomplate -i '{{ "v1.1.1" | semver.CheckConstraint "> 1.0" }}' +true +``` diff --git a/funcs.go b/funcs.go index 8a665cdd5..efe7d6bcd 100644 --- a/funcs.go +++ b/funcs.go @@ -41,6 +41,7 @@ func CreateFuncs(ctx context.Context, d *data.Data) template.FuncMap { addToMap(f, funcs.CreateCollFuncs(ctx)) addToMap(f, funcs.CreateUUIDFuncs(ctx)) addToMap(f, funcs.CreateRandomFuncs(ctx)) + addToMap(f, funcs.CreateSemverFuncs(ctx)) return f } diff --git a/funcs/semver.go b/funcs/semver.go new file mode 100644 index 000000000..0212c9987 --- /dev/null +++ b/funcs/semver.go @@ -0,0 +1,40 @@ +package funcs + +import ( + "context" + + "github.com/Masterminds/semver/v3" +) + +// CreateSemverFuncs - +func CreateSemverFuncs(ctx context.Context) map[string]interface{} { + ns := &SemverFuncs{ctx} + return map[string]interface{}{ + "semver": func() interface{} { return ns }, + } +} + +// SemverFuncs - +type SemverFuncs struct { + ctx context.Context +} + +// Semver - +func (SemverFuncs) Semver(version string) (*semver.Version, error) { + return semver.NewVersion(version) +} + +// CheckConstraint - +func (SemverFuncs) CheckConstraint(constraint, in string) (bool, error) { + c, err := semver.NewConstraint(constraint) + if err != nil { + return false, err + } + + v, err := semver.NewVersion(in) + if err != nil { + return false, err + } + + return c.Check(v), nil +} diff --git a/funcs/semver_test.go b/funcs/semver_test.go new file mode 100644 index 000000000..f10aad5cf --- /dev/null +++ b/funcs/semver_test.go @@ -0,0 +1,61 @@ +package funcs + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSemverFuncs_MatchConstraint(t *testing.T) { + tests := []struct { + name string + constraint string + in string + want bool + wantErr bool + }{ + { + name: "mached constraint", + constraint: ">=1.0.0", + in: "v1.1.1", + want: true, + wantErr: false, + }, + { + name: "not matched constraint", + constraint: "<1.0.0", + in: "v1.1.1", + want: false, + wantErr: false, + }, + { + name: "wrong constraint", + constraint: "abc", + in: "v1.1.1", + want: false, + wantErr: true, + }, + { + name: "wrong in", + constraint: ">1.0.0", + in: "va.b.c", + want: false, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := SemverFuncs{ + ctx: context.Background(), + } + got, err := s.CheckConstraint(tt.constraint, tt.in) + if tt.wantErr { + assert.Errorf(t, err, "SemverFuncs.CheckConstraint() error = %v, wantErr %v", err, tt.wantErr) + } else { + assert.NoErrorf(t, err, "SemverFuncs.CheckConstraint() error = %v, wantErr %v", err, tt.wantErr) + assert.Equal(t, tt.want, got) + } + }) + } +}