mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-01-30 04:50:45 +02:00
feat(ko): support annotations and user (#5227)
Add support for the newly added annotations and user options in [ko v0.17.0](https://github.com/ko-build/ko/releases/tag/v0.17.0)
This commit is contained in:
parent
ca5ad8c5ed
commit
d722aac36b
@ -166,6 +166,8 @@ type buildOptions struct {
|
||||
platforms []string
|
||||
baseImage string
|
||||
labels map[string]string
|
||||
annotations map[string]string
|
||||
user string
|
||||
tags []string
|
||||
creationTime *v1.Time
|
||||
koDataCreationTime *v1.Time
|
||||
@ -226,6 +228,12 @@ func (o *buildOptions) makeBuilder(ctx *context.Context) (*build.Caching, error)
|
||||
for k, v := range o.labels {
|
||||
buildOptions = append(buildOptions, build.WithLabel(k, v))
|
||||
}
|
||||
for k, v := range o.annotations {
|
||||
buildOptions = append(buildOptions, build.WithAnnotation(k, v))
|
||||
}
|
||||
if o.user != "" {
|
||||
buildOptions = append(buildOptions, build.WithUser(o.user))
|
||||
}
|
||||
switch o.sbom {
|
||||
case "spdx":
|
||||
buildOptions = append(buildOptions, build.WithSPDX("devel"))
|
||||
@ -356,6 +364,7 @@ func buildBuildOptions(ctx *context.Context, cfg config.Ko) (*buildOptions, erro
|
||||
platforms: cfg.Platforms,
|
||||
sbom: cfg.SBOM,
|
||||
imageRepo: cfg.Repository,
|
||||
user: cfg.User,
|
||||
}
|
||||
|
||||
tags, err := applyTemplate(ctx, cfg.Tags)
|
||||
@ -381,14 +390,19 @@ func buildBuildOptions(ctx *context.Context, cfg config.Ko) (*buildOptions, erro
|
||||
}
|
||||
|
||||
if len(cfg.Labels) > 0 {
|
||||
opts.labels = make(map[string]string, len(cfg.Labels))
|
||||
for k, v := range cfg.Labels {
|
||||
tv, err := tmpl.New(ctx).Apply(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts.labels[k] = tv
|
||||
labels, err := applyTemplateToMapValues(ctx, cfg.Labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts.labels = labels
|
||||
}
|
||||
|
||||
if len(cfg.Annotations) > 0 {
|
||||
annotations, err := applyTemplateToMapValues(ctx, cfg.Annotations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts.annotations = annotations
|
||||
}
|
||||
|
||||
if len(cfg.Env) > 0 {
|
||||
@ -429,7 +443,7 @@ func removeEmpty(strs []string) []string {
|
||||
}
|
||||
|
||||
func applyTemplate(ctx *context.Context, templateable []string) ([]string, error) {
|
||||
var templated []string
|
||||
templated := make([]string, 0, len(templateable))
|
||||
for _, t := range templateable {
|
||||
tlf, err := tmpl.New(ctx).Apply(t)
|
||||
if err != nil {
|
||||
@ -440,6 +454,18 @@ func applyTemplate(ctx *context.Context, templateable []string) ([]string, error
|
||||
return templated, nil
|
||||
}
|
||||
|
||||
func applyTemplateToMapValues(ctx *context.Context, templateable map[string]string) (map[string]string, error) {
|
||||
templated := make(map[string]string, len(templateable))
|
||||
for k, v := range templateable {
|
||||
tv, err := tmpl.New(ctx).Apply(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
templated[k] = tv
|
||||
}
|
||||
return templated, nil
|
||||
}
|
||||
|
||||
func getTimeFromTemplate(ctx *context.Context, t string) (*v1.Time, error) {
|
||||
epoch, err := tmpl.New(ctx).Apply(t)
|
||||
if err != nil {
|
||||
|
@ -2,6 +2,7 @@ package ko
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -165,55 +166,63 @@ func TestPublishPipeSuccess(t *testing.T) {
|
||||
"org.opencontainers.image.vendor": "Chainguard",
|
||||
"org.opencontainers.image.created": ".*",
|
||||
}
|
||||
baseImageAnnotations := map[string]string{
|
||||
"org.opencontainers.image.base.name": ".*",
|
||||
"org.opencontainers.image.base.digest": ".*",
|
||||
}
|
||||
|
||||
table := []struct {
|
||||
Name string
|
||||
SBOM string
|
||||
BaseImage string
|
||||
Labels map[string]string
|
||||
ExpectedLabels map[string]string
|
||||
Platforms []string
|
||||
Tags []string
|
||||
CreationTime string
|
||||
KoDataCreationTime string
|
||||
Name string
|
||||
SBOM string
|
||||
BaseImage string
|
||||
Labels map[string]string
|
||||
ExpectedLabels map[string]string
|
||||
Annotations map[string]string
|
||||
ExpectedAnnotations map[string]string
|
||||
User string
|
||||
Platforms []string
|
||||
Tags []string
|
||||
CreationTime string
|
||||
KoDataCreationTime string
|
||||
}{
|
||||
{
|
||||
// Must be first as others add an SBOM for the same image
|
||||
Name: "sbom-none",
|
||||
SBOM: "none",
|
||||
ExpectedLabels: chainguardStaticLabels,
|
||||
Name: "sbom-none",
|
||||
SBOM: "none",
|
||||
},
|
||||
{
|
||||
Name: "sbom-spdx",
|
||||
SBOM: "spdx",
|
||||
ExpectedLabels: chainguardStaticLabels,
|
||||
Name: "sbom-spdx",
|
||||
SBOM: "spdx",
|
||||
},
|
||||
{
|
||||
Name: "base-image-is-not-index",
|
||||
BaseImage: "alpine:latest@sha256:c0d488a800e4127c334ad20d61d7bc21b4097540327217dfab52262adc02380c",
|
||||
},
|
||||
{
|
||||
Name: "multiple-platforms",
|
||||
Platforms: []string{"linux/amd64", "linux/arm64"},
|
||||
ExpectedLabels: chainguardStaticLabels,
|
||||
Name: "multiple-platforms",
|
||||
Platforms: []string{"linux/amd64", "linux/arm64"},
|
||||
},
|
||||
{
|
||||
Name: "labels",
|
||||
Labels: map[string]string{"foo": "bar", "project": "{{.ProjectName}}"},
|
||||
ExpectedLabels: mapsMerge(
|
||||
map[string]string{"foo": "bar", "project": "test"},
|
||||
chainguardStaticLabels,
|
||||
),
|
||||
Name: "labels",
|
||||
Labels: map[string]string{"foo": "bar", "project": "{{.ProjectName}}"},
|
||||
ExpectedLabels: map[string]string{"foo": "bar", "project": "test"},
|
||||
},
|
||||
{
|
||||
Name: "creation-time",
|
||||
CreationTime: "1672531200",
|
||||
ExpectedLabels: chainguardStaticLabels,
|
||||
Name: "annotations",
|
||||
Annotations: map[string]string{"foo": "bar", "project": "{{.ProjectName}}"},
|
||||
ExpectedAnnotations: map[string]string{"foo": "bar", "project": "test"},
|
||||
},
|
||||
{
|
||||
Name: "user",
|
||||
User: "1234:1234",
|
||||
},
|
||||
{
|
||||
Name: "creation-time",
|
||||
CreationTime: "1672531200",
|
||||
},
|
||||
{
|
||||
Name: "kodata-creation-time",
|
||||
KoDataCreationTime: "1672531200",
|
||||
ExpectedLabels: chainguardStaticLabels,
|
||||
},
|
||||
{
|
||||
Name: "tag-templates",
|
||||
@ -221,7 +230,6 @@ func TestPublishPipeSuccess(t *testing.T) {
|
||||
"{{if not .Prerelease }}{{.Version}}{{ end }}",
|
||||
" ", // empty
|
||||
},
|
||||
ExpectedLabels: chainguardStaticLabels,
|
||||
},
|
||||
{
|
||||
Name: "tag-template-eval-empty",
|
||||
@ -229,7 +237,6 @@ func TestPublishPipeSuccess(t *testing.T) {
|
||||
"{{.Version}}",
|
||||
"{{if .Prerelease }}latest{{ end }}",
|
||||
},
|
||||
ExpectedLabels: chainguardStaticLabels,
|
||||
},
|
||||
}
|
||||
|
||||
@ -260,6 +267,8 @@ func TestPublishPipeSuccess(t *testing.T) {
|
||||
BaseImage: table.BaseImage,
|
||||
Repository: repository,
|
||||
Labels: table.Labels,
|
||||
Annotations: table.Annotations,
|
||||
User: table.User,
|
||||
Platforms: table.Platforms,
|
||||
Tags: table.Tags,
|
||||
CreationTime: table.CreationTime,
|
||||
@ -270,6 +279,14 @@ func TestPublishPipeSuccess(t *testing.T) {
|
||||
},
|
||||
}, testctx.WithVersion("1.2.0"))
|
||||
|
||||
if table.BaseImage == "" {
|
||||
if table.User == "" {
|
||||
table.User = "65532"
|
||||
}
|
||||
table.ExpectedLabels = mergeMaps(table.ExpectedLabels, chainguardStaticLabels)
|
||||
}
|
||||
table.ExpectedAnnotations = mergeMaps(table.ExpectedAnnotations, baseImageAnnotations)
|
||||
|
||||
require.NoError(t, Pipe{}.Default(ctx))
|
||||
require.NoError(t, Pipe{}.Publish(ctx))
|
||||
|
||||
@ -305,6 +322,8 @@ func TestPublishPipeSuccess(t *testing.T) {
|
||||
imf, err := index.IndexManifest()
|
||||
require.NoError(t, err)
|
||||
|
||||
compareMaps(t, table.ExpectedAnnotations, imf.Annotations)
|
||||
|
||||
platforms := make([]string, 0, len(imf.Manifests))
|
||||
for _, mf := range imf.Manifests {
|
||||
platforms = append(platforms, mf.Platform.String())
|
||||
@ -351,16 +370,24 @@ func TestPublishPipeSuccess(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
mf, err := image.Manifest()
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedAnnotations := table.ExpectedAnnotations
|
||||
if table.BaseImage == "" {
|
||||
expectedAnnotations = mergeMaps(
|
||||
expectedAnnotations,
|
||||
chainguardStaticLabels,
|
||||
)
|
||||
}
|
||||
compareMaps(t, expectedAnnotations, mf.Annotations)
|
||||
|
||||
configFile, err := image.ConfigFile()
|
||||
require.NoError(t, err)
|
||||
require.GreaterOrEqual(t, len(configFile.History), 3)
|
||||
|
||||
require.Len(t, configFile.Config.Labels, len(table.ExpectedLabels))
|
||||
for k, v := range table.ExpectedLabels {
|
||||
got, ok := configFile.Config.Labels[k]
|
||||
require.True(t, ok, "missing label")
|
||||
require.Regexp(t, v, got)
|
||||
}
|
||||
compareMaps(t, table.ExpectedLabels, configFile.Config.Labels)
|
||||
require.Equal(t, table.User, configFile.Config.User)
|
||||
|
||||
var creationTime time.Time
|
||||
if table.CreationTime != "" {
|
||||
@ -603,13 +630,22 @@ func TestApplyTemplate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func mapsMerge(m1, m2 map[string]string) map[string]string {
|
||||
func mergeMaps(ms ...map[string]string) map[string]string {
|
||||
result := map[string]string{}
|
||||
for k, v := range m1 {
|
||||
result[k] = v
|
||||
}
|
||||
for k, v := range m2 {
|
||||
result[k] = v
|
||||
for _, m := range ms {
|
||||
if m != nil {
|
||||
maps.Copy(result, m)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func compareMaps(t *testing.T, expected, actual map[string]string) {
|
||||
t.Helper()
|
||||
require.Len(t, actual, len(expected), "expected: %v", expected)
|
||||
for k, v := range expected {
|
||||
got, ok := actual[k]
|
||||
require.True(t, ok, "missing key: %s", k)
|
||||
require.Regexp(t, v, got, "key: %s", k)
|
||||
}
|
||||
}
|
||||
|
@ -369,6 +369,8 @@ type Ko struct {
|
||||
WorkingDir string `yaml:"working_dir,omitempty" json:"working_dir,omitempty"`
|
||||
BaseImage string `yaml:"base_image,omitempty" json:"base_image,omitempty"`
|
||||
Labels map[string]string `yaml:"labels,omitempty" json:"labels,omitempty"`
|
||||
Annotations map[string]string `yaml:"annotations,omitempty" json:"annotations,omitempty"`
|
||||
User string `yaml:"user,omitempty" json:"user,omitempty"`
|
||||
Repository string `yaml:"repository,omitempty" json:"repository,omitempty"`
|
||||
Platforms []string `yaml:"platforms,omitempty" json:"platforms,omitempty"`
|
||||
Tags []string `yaml:"tags,omitempty" json:"tags,omitempty"`
|
||||
|
@ -46,6 +46,13 @@ kos:
|
||||
labels:
|
||||
foo: bar
|
||||
|
||||
# Annotations for the OCI manifest.
|
||||
annotations:
|
||||
foo: bar
|
||||
|
||||
# The default user the image should be run as.
|
||||
user: "1234:1234"
|
||||
|
||||
# Repository to push to.
|
||||
#
|
||||
# Default: '$KO_DOCKER_REPO'.
|
||||
|
9
www/docs/static/schema-pro.json
generated
vendored
9
www/docs/static/schema-pro.json
generated
vendored
@ -1929,6 +1929,15 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"annotations": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
},
|
||||
"repository": {
|
||||
"type": "string"
|
||||
},
|
||||
|
9
www/docs/static/schema.json
generated
vendored
9
www/docs/static/schema.json
generated
vendored
@ -1442,6 +1442,15 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"annotations": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
},
|
||||
"repository": {
|
||||
"type": "string"
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user