bake: add semvercmp func to stdlib
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/docker/cli/cli/config"
|
||||
"github.com/hashicorp/go-cty-funcs/cidr"
|
||||
"github.com/hashicorp/go-cty-funcs/crypto"
|
||||
@@ -103,6 +104,7 @@ var stdlibFunctions = []funcDef{
|
||||
{name: "reverselist", fn: stdlib.ReverseListFunc},
|
||||
{name: "rsadecrypt", fn: crypto.RsaDecryptFunc, descriptionAlt: `Decrypts an RSA-encrypted ciphertext.`},
|
||||
{name: "sanitize", factory: sanitizeFunc},
|
||||
{name: "semvercmp", factory: semvercmpFunc},
|
||||
{name: "sethaselement", fn: stdlib.SetHasElementFunc},
|
||||
{name: "setintersection", fn: stdlib.SetIntersectionFunc},
|
||||
{name: "setproduct", fn: stdlib.SetProductFunc},
|
||||
@@ -246,6 +248,36 @@ func sanitizeFunc() function.Function {
|
||||
})
|
||||
}
|
||||
|
||||
// semvercmpFunc constructs a function that checks if a version satisfies a
|
||||
// constraint.
|
||||
func semvercmpFunc() function.Function {
|
||||
return function.New(&function.Spec{
|
||||
Description: `Returns true if version satisfies a constraint.`,
|
||||
Params: []function.Parameter{
|
||||
{
|
||||
Name: "version",
|
||||
Type: cty.String,
|
||||
},
|
||||
{
|
||||
Name: "contraint",
|
||||
Type: cty.String,
|
||||
},
|
||||
},
|
||||
Type: function.StaticReturnType(cty.Bool),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||
version, err := semver.NewVersion(args[0].AsString())
|
||||
if err != nil {
|
||||
return cty.UnknownVal(cty.Bool), err
|
||||
}
|
||||
constraint, err := semver.NewConstraint(args[1].AsString())
|
||||
if err != nil {
|
||||
return cty.UnknownVal(cty.Bool), err
|
||||
}
|
||||
return cty.BoolVal(constraint.Check(version)), nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// timestampFunc constructs a function that returns a string representation of the current date and time.
|
||||
//
|
||||
// This function was imported from terraform's datetime utilities.
|
||||
|
||||
@@ -205,3 +205,61 @@ func TestHomedir(t *testing.T) {
|
||||
require.NotEmpty(t, home.AsString())
|
||||
require.True(t, filepath.IsAbs(home.AsString()))
|
||||
}
|
||||
|
||||
func TestSemverCmp(t *testing.T) {
|
||||
type testCase struct {
|
||||
version cty.Value
|
||||
constraint cty.Value
|
||||
want cty.Value
|
||||
wantErr bool
|
||||
}
|
||||
tests := map[string]testCase{
|
||||
"valid constraint satisfied": {
|
||||
version: cty.StringVal("1.2.3"),
|
||||
constraint: cty.StringVal(">= 1.0.0"),
|
||||
want: cty.BoolVal(true),
|
||||
},
|
||||
"valid constraint not satisfied": {
|
||||
version: cty.StringVal("2.1.0"),
|
||||
constraint: cty.StringVal("< 2.0.0"),
|
||||
want: cty.BoolVal(false),
|
||||
},
|
||||
"valid constraint satisfied without patch": {
|
||||
version: cty.StringVal("3.22"),
|
||||
constraint: cty.StringVal(">= 3.20"),
|
||||
want: cty.BoolVal(true),
|
||||
},
|
||||
"invalid version": {
|
||||
version: cty.StringVal("not-a-version"),
|
||||
constraint: cty.StringVal(">= 1.0.0"),
|
||||
wantErr: true,
|
||||
},
|
||||
"invalid constraint": {
|
||||
version: cty.StringVal("1.2.3"),
|
||||
constraint: cty.StringVal("not-a-constraint"),
|
||||
wantErr: true,
|
||||
},
|
||||
"empty version": {
|
||||
version: cty.StringVal(""),
|
||||
constraint: cty.StringVal(">= 1.0.0"),
|
||||
wantErr: true,
|
||||
},
|
||||
"empty constraint": {
|
||||
version: cty.StringVal("1.2.3"),
|
||||
constraint: cty.StringVal(""),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for name, test := range tests {
|
||||
name, test := name, test
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, err := semvercmpFunc().Call([]cty.Value{test.version, test.constraint})
|
||||
if test.wantErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, test.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ title: Bake standard library functions
|
||||
| [`reverselist`](#reverselist) | Returns the given list with its elements in reverse order. |
|
||||
| [`rsadecrypt`](#rsadecrypt) | Decrypts an RSA-encrypted ciphertext. |
|
||||
| [`sanitize`](#sanitize) | Replaces all non-alphanumeric characters with a underscore, leaving only characters that are valid for a Bake target name. |
|
||||
| [`semvercmp`](#semvercmp) | Returns true if version satisfies a constraint. |
|
||||
| [`sethaselement`](#sethaselement) | Returns true if the given set contains the given element, or false otherwise. |
|
||||
| [`setintersection`](#setintersection) | Returns the intersection of all given sets. |
|
||||
| [`setproduct`](#setproduct) | Calculates the cartesian product of two or more sets. |
|
||||
@@ -1065,6 +1066,31 @@ target "webapp-dev" {
|
||||
}
|
||||
```
|
||||
|
||||
## `semvercmp`
|
||||
|
||||
This function checks if a semantic version fits within a set of constraints.
|
||||
See [Checking Version Constraints](https://github.com/Masterminds/semver?tab=readme-ov-file#checking-version-constraints)
|
||||
for details.
|
||||
|
||||
```hcl
|
||||
# docker-bake.hcl
|
||||
variable "ALPINE_VERSION" {
|
||||
default = "3.23"
|
||||
}
|
||||
|
||||
target "webapp-dev" {
|
||||
dockerfile = "Dockerfile.webapp"
|
||||
platforms = semvercmp(ALPINE_VERSION, ">= 3.20") ? [
|
||||
"linux/amd64",
|
||||
"linux/arm64",
|
||||
"linux/riscv64"
|
||||
] : [
|
||||
"linux/amd64",
|
||||
"linux/arm64"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## `sethaselement`
|
||||
|
||||
```hcl
|
||||
|
||||
Reference in New Issue
Block a user