1
0
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:
Maxime Brunet 2024-10-27 19:01:09 +00:00 committed by GitHub
parent ca5ad8c5ed
commit d722aac36b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 139 additions and 50 deletions

View File

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

View File

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

View File

@ -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"`

View File

@ -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
View File

@ -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
View File

@ -1442,6 +1442,15 @@
},
"type": "object"
},
"annotations": {
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"user": {
"type": "string"
},
"repository": {
"type": "string"
},