Skip to content

KUBESAW-201: Replace go-bindata with go:embed #1161

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 2, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ var (
setupLog = ctrl.Log.WithName("setup")
)

const memberClientTimeout = 3 * time.Second
const (
memberClientTimeout = 3 * time.Second
userTierRootDir = "templates/usertiers"
)

func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
Expand Down Expand Up @@ -434,8 +437,7 @@ func main() { // nolint:gocyclo

// create or update all UserTiers on the cluster at startup
setupLog.Info("Creating/updating the UserTier resources")
usertierAssets := assets.NewAssets(usertiers.AssetNames, usertiers.Asset)
if err := usertiers.CreateOrUpdateResources(ctx, mgr.GetScheme(), mgr.GetClient(), namespace, usertierAssets); err != nil {
if err := usertiers.CreateOrUpdateResources(ctx, mgr.GetScheme(), mgr.GetClient(), namespace, deploy.UserTiersFS, userTierRootDir); err != nil {
setupLog.Error(err, "")
os.Exit(1)
}
Expand Down
7 changes: 6 additions & 1 deletion deploy/resources.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package deploy

import "embed"
import (
"embed"
)

//go:embed templates/notificationtemplates/*
var NotificationTemplateFS embed.FS
Expand All @@ -10,3 +12,6 @@ var ToolchainClusterTemplateFS embed.FS

//go:embed templates/registration-service/*
var RegistrationServiceFS embed.FS

//go:embed templates/usertiers/*
var UserTiersFS embed.FS
6 changes: 0 additions & 6 deletions make/go.mk
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,6 @@ generate-assets: go-bindata
@rm ./pkg/templates/nstemplatetiers/nstemplatetier_assets.go 2>/dev/null || true
@$(GO_BINDATA) -pkg nstemplatetiers -o ./pkg/templates/nstemplatetiers/nstemplatetier_assets.go -nometadata -nocompress -prefix $(NSTEMPLATES_BASEDIR) $(NSTEMPLATES_BASEDIR)/...

@echo "generating bindata for files in $(USERTEMPLATES_BASEDIR) ..."
@rm ./pkg/templates/usertiers/usertier_assets.go 2>/dev/null || true
@$(GO_BINDATA) -pkg usertiers -o ./pkg/templates/usertiers/usertier_assets.go -nometadata -nocompress -prefix $(USERTEMPLATES_BASEDIR) $(USERTEMPLATES_BASEDIR)/...
@echo "generating bindata for files in $(USERTEMPLATES_TEST_BASEDIR) ..."
@rm ./test/templates/usertiers/usertier_assets.go 2>/dev/null || true
@$(GO_BINDATA) -pkg usertiers_test -o ./test/templates/usertiers/usertier_assets.go -nometadata -nocompress -prefix $(USERTEMPLATES_TEST_BASEDIR) -ignore doc.go $(USERTEMPLATES_TEST_BASEDIR)/...

.PHONY: verify-dependencies
## Runs commands to verify after the updated dependecies of toolchain-common/API(go mod replace), if the repo needs any changes to be made
Expand Down
6 changes: 6 additions & 0 deletions pkg/templates/usertiers/test_resources.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package usertiers

import "embed"

//go:embed testtemplates/testusertiers/*
var TestUserTierTemplatesFS embed.FS
48 changes: 36 additions & 12 deletions pkg/templates/usertiers/usertier_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import (
"context"
"embed"
"fmt"
"io/fs"
"reflect"
"strings"

toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1"
"github.com/codeready-toolchain/host-operator/pkg/templates/assets"
commonclient "github.com/codeready-toolchain/toolchain-common/pkg/client"
commonTemplate "github.com/codeready-toolchain/toolchain-common/pkg/template"

Expand All @@ -25,10 +26,10 @@

// CreateOrUpdateResources generates the UserTier resources,
// then uses the manager's client to create or update the resources on the cluster.
func CreateOrUpdateResources(ctx context.Context, s *runtime.Scheme, client runtimeclient.Client, namespace string, assets assets.Assets) error {
func CreateOrUpdateResources(ctx context.Context, s *runtime.Scheme, client runtimeclient.Client, namespace string, userTiersFS embed.FS, root string) error {

// initialize tier generator, loads templates from assets
generator, err := newUserTierGenerator(s, client, namespace, assets)
generator, err := newUserTierGenerator(s, client, namespace, userTiersFS, root)
if err != nil {
return errors.Wrap(err, "unable to create UserTier generator")
}
Expand Down Expand Up @@ -66,9 +67,9 @@
}

// newUserTierGenerator loads templates from the provided assets and processes the UserTiers
func newUserTierGenerator(s *runtime.Scheme, client runtimeclient.Client, namespace string, assets assets.Assets) (*tierGenerator, error) {
// load templates from assets
templatesByTier, err := loadTemplatesByTiers(assets)
func newUserTierGenerator(s *runtime.Scheme, client runtimeclient.Client, namespace string, userTiersFS embed.FS, root string) (*tierGenerator, error) {
// load templates
templatesByTier, err := loadTemplatesByTiers(userTiersFS, root)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -113,24 +114,32 @@
// The output is a map of `tierData` indexed by tier.
// Each `tierData` object contains template objects for the tier.
// Each `template` object contains a `revision` (`string`) and the `content` of the template to apply (`[]byte`)
func loadTemplatesByTiers(assets assets.Assets) (map[string]*tierData, error) {
func loadTemplatesByTiers(userTierFS embed.FS, root string) (map[string]*tierData, error) {
paths, err := getAllFileNames(&userTierFS, root)
if err != nil {
return nil, err
}

Check warning on line 121 in pkg/templates/usertiers/usertier_generator.go

View check run for this annotation

Codecov / codecov/patch

pkg/templates/usertiers/usertier_generator.go#L120-L121

Added lines #L120 - L121 were not covered by tests
if len(paths) == 0 {
return nil, fmt.Errorf("could not find any user templates")
}

Check warning on line 124 in pkg/templates/usertiers/usertier_generator.go

View check run for this annotation

Codecov / codecov/patch

pkg/templates/usertiers/usertier_generator.go#L123-L124

Added lines #L123 - L124 were not covered by tests

results := make(map[string]*tierData)
for _, name := range assets.Names() {
for _, name := range paths {
// split the name using the `/` separator
parts := strings.Split(name, "/")
// skip any name that does not have 2 parts
if len(parts) != 2 {
if len(parts) != 4 {
return nil, fmt.Errorf("unable to load templates: invalid name format for file '%s'", name)
}
tier := parts[0]
filename := parts[1]
tier := parts[2]
filename := parts[3]
if _, exists := results[tier]; !exists {
results[tier] = &tierData{
name: tier,
rawTemplates: &templates{},
}
}
content, err := assets.Asset(name)
content, err := userTierFS.ReadFile(name)
if err != nil {
return nil, errors.Wrapf(err, "unable to load templates")
}
Expand Down Expand Up @@ -253,3 +262,18 @@
}
return toolchainObjects, nil
}

func getAllFileNames(notificationFS *embed.FS, root string) (files []string, err error) {

if err := fs.WalkDir(notificationFS, root, func(path string, d fs.DirEntry, err error) error {
if d.IsDir() {
return nil
}
files = append(files, path)
return nil
}); err != nil {
return nil, err
}

Check warning on line 276 in pkg/templates/usertiers/usertier_generator.go

View check run for this annotation

Codecov / codecov/patch

pkg/templates/usertiers/usertier_generator.go#L274-L276

Added lines #L274 - L276 were not covered by tests

return files, nil
}
37 changes: 10 additions & 27 deletions pkg/templates/usertiers/usertier_generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import (

toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1"
"github.com/codeready-toolchain/host-operator/pkg/apis"
"github.com/codeready-toolchain/host-operator/pkg/templates/assets"
"github.com/codeready-toolchain/host-operator/pkg/templates/usertiers"
testusertiers "github.com/codeready-toolchain/host-operator/test/templates/usertiers"
commontest "github.com/codeready-toolchain/toolchain-common/pkg/test"

"github.com/pkg/errors"
Expand All @@ -24,15 +22,17 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)

const (
testRoot = "testtemplates/testusertiers"
)

func TestCreateOrUpdateResources(t *testing.T) {

s := scheme.Scheme
err := apis.AddToScheme(s)
require.NoError(t, err)
logf.SetLogger(zap.New(zap.UseDevMode(true)))

testassets := assets.NewAssets(testusertiers.AssetNames, testusertiers.Asset)

t.Run("ok", func(t *testing.T) {

t.Run("create only", func(t *testing.T) {
Expand All @@ -45,10 +45,8 @@ func TestCreateOrUpdateResources(t *testing.T) {
require.NoError(t, err)
require.Empty(t, userTiers.Items)

assets := assets.NewAssets(testusertiers.AssetNames, testusertiers.Asset)

// when
err := usertiers.CreateOrUpdateResources(context.TODO(), s, clt, namespace, assets)
err := usertiers.CreateOrUpdateResources(context.TODO(), s, clt, namespace, usertiers.TestUserTierTemplatesFS, testRoot)

// then
require.NoError(t, err)
Expand Down Expand Up @@ -77,11 +75,11 @@ func TestCreateOrUpdateResources(t *testing.T) {
clt := commontest.NewFakeClient(t)

// when
err := usertiers.CreateOrUpdateResources(context.TODO(), s, clt, namespace, testassets)
err := usertiers.CreateOrUpdateResources(context.TODO(), s, clt, namespace, usertiers.TestUserTierTemplatesFS, testRoot)
require.NoError(t, err)

// when calling CreateOrUpdateResources a second time
err = usertiers.CreateOrUpdateResources(context.TODO(), s, clt, namespace, testassets)
err = usertiers.CreateOrUpdateResources(context.TODO(), s, clt, namespace, usertiers.TestUserTierTemplatesFS, testRoot)

// then
require.NoError(t, err)
Expand Down Expand Up @@ -109,20 +107,6 @@ func TestCreateOrUpdateResources(t *testing.T) {

namespace := "host-operator" + uuid.Must(uuid.NewV4()).String()[:7]

t.Run("failed to read assets", func(t *testing.T) {
// given
fakeAssets := assets.NewAssets(testusertiers.AssetNames, func(name string) ([]byte, error) {
// error occurs when fetching the content of the 'tier.yaml' template
return nil, errors.Errorf("an error")
})
clt := commontest.NewFakeClient(t)
// when
err := usertiers.CreateOrUpdateResources(context.TODO(), s, clt, namespace, fakeAssets)
// then
require.Error(t, err)
assert.Equal(t, "unable to create UserTier generator: unable to load templates: an error", err.Error()) // error occurred while creating TierTemplate resources
})

t.Run("usertiers", func(t *testing.T) {

t.Run("failed to create usertiers", func(t *testing.T) {
Expand All @@ -135,9 +119,8 @@ func TestCreateOrUpdateResources(t *testing.T) {
}
return clt.Client.Create(ctx, obj, opts...)
}
assets := assets.NewAssets(testusertiers.AssetNames, testusertiers.Asset)
// when
err := usertiers.CreateOrUpdateResources(context.TODO(), s, clt, namespace, assets)
err := usertiers.CreateOrUpdateResources(context.TODO(), s, clt, namespace, usertiers.TestUserTierTemplatesFS, testRoot)
// then
require.Error(t, err)
assert.Regexp(t, "unable to create UserTiers: unable to create or update the '\\w+' UserTier: unable to create resource of kind: UserTier, version: v1alpha1: an error", err.Error())
Expand All @@ -159,9 +142,9 @@ func TestCreateOrUpdateResources(t *testing.T) {
}
return clt.Client.Update(ctx, obj, opts...)
}
testassets := assets.NewAssets(testusertiers.AssetNames, testusertiers.Asset)

// when
err := usertiers.CreateOrUpdateResources(context.TODO(), s, clt, namespace, testassets)
err := usertiers.CreateOrUpdateResources(context.TODO(), s, clt, namespace, usertiers.TestUserTierTemplatesFS, testRoot)
// then
require.Error(t, err)
assert.Contains(t, err.Error(), "unable to create UserTiers: unable to create or update the 'advanced' UserTier: unable to create resource of kind: UserTier, version: v1alpha1: unable to update the resource")
Expand Down
81 changes: 10 additions & 71 deletions pkg/templates/usertiers/usertier_generator_whitebox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ package usertiers

import (
"bytes"
"fmt"
"testing"
texttemplate "text/template"

toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1"
"github.com/codeready-toolchain/host-operator/deploy"
"github.com/codeready-toolchain/host-operator/pkg/apis"
"github.com/codeready-toolchain/host-operator/pkg/templates/assets"
testusertiers "github.com/codeready-toolchain/host-operator/test/templates/usertiers"

"github.com/gofrs/uuid"
"github.com/stretchr/testify/assert"
Expand All @@ -36,17 +34,20 @@ var expectedTestTiers = []string{
"base",
}

const (
rootDir = "templates/usertiers"
testRoot = "testtemplates/testusertiers"
)

func TestLoadTemplatesByTiers(t *testing.T) {

logf.SetLogger(zap.New(zap.UseDevMode(true)))

t.Run("ok", func(t *testing.T) {

t.Run("with prod assets", func(t *testing.T) {
// given
assets := assets.NewAssets(AssetNames, Asset)
// when
tmpls, err := loadTemplatesByTiers(assets)
tmpls, err := loadTemplatesByTiers(deploy.UserTiersFS, rootDir)
// then
require.NoError(t, err)
require.Len(t, tmpls, len(expectedProdTiers))
Expand All @@ -64,10 +65,8 @@ func TestLoadTemplatesByTiers(t *testing.T) {
})

t.Run("with test assets", func(t *testing.T) {
// given
assets := assets.NewAssets(testusertiers.AssetNames, testusertiers.Asset)
// when
tmpls, err := loadTemplatesByTiers(assets)
tmpls, err := loadTemplatesByTiers(TestUserTierTemplatesFS, testRoot)
// then
require.NoError(t, err)
require.Len(t, tmpls, 2)
Expand All @@ -91,64 +90,6 @@ func TestLoadTemplatesByTiers(t *testing.T) {
}
})
})

t.Run("failures", func(t *testing.T) {

t.Run("missing asset", func(t *testing.T) {
// given
fakeAssets := func(name string) ([]byte, error) {
return nil, fmt.Errorf("an error occurred")
}
assets := assets.NewAssets(testusertiers.AssetNames, fakeAssets)
// when
_, err := loadTemplatesByTiers(assets)
// then
require.Error(t, err)
assert.Contains(t, err.Error(), "unable to load templates: an error occurred")
})

t.Run("invalid name format", func(t *testing.T) {
// given
fakeAssetNames := func() []string {
return []string{`.DS_Store`} // '/advanced/foo.yaml' is not a valid filename
}
fakeAssets := func(name string) ([]byte, error) {
switch name {
case ".DS_Store":
return []byte(`foo:bar`), nil // just make sure the asset exists
default:
return testusertiers.Asset(name)
}
}
assets := assets.NewAssets(fakeAssetNames, fakeAssets)
// when
_, err := loadTemplatesByTiers(assets)
// then
require.Error(t, err)
require.EqualError(t, err, "unable to load templates: invalid name format for file '.DS_Store'")
})

t.Run("invalid filename scope", func(t *testing.T) {
// given
fakeAssetNames := func() []string {
return []string{`advanced/foo.yaml`} // '/advanced/foo.yaml' is not a valid filename
}
fakeAssets := func(name string) ([]byte, error) {
switch name {
case "advanced/foo.yaml":
return []byte(`foo:bar`), nil // just make sure the asset exists
default:
return testusertiers.Asset(name)
}
}
assets := assets.NewAssets(fakeAssetNames, fakeAssets)
// when
_, err := loadTemplatesByTiers(assets)
// then
require.Error(t, err)
assert.Contains(t, err.Error(), "unable to load templates: unknown scope for file 'advanced/foo.yaml'")
})
})
}

func TestNewUserTier(t *testing.T) {
Expand All @@ -162,9 +103,8 @@ func TestNewUserTier(t *testing.T) {
t.Run("with prod assets", func(t *testing.T) {
// given
namespace := "host-operator-" + uuid.Must(uuid.NewV4()).String()[:7]
assets := assets.NewAssets(AssetNames, Asset)
// when
tc, err := newUserTierGenerator(s, nil, namespace, assets)
tc, err := newUserTierGenerator(s, nil, namespace, deploy.UserTiersFS, rootDir)
require.NoError(t, err)
// then
require.Len(t, tc.templatesByTier, len(expectedProdTiers))
Expand Down Expand Up @@ -202,8 +142,7 @@ func TestNewUserTier(t *testing.T) {
t.Run("with test assets", func(t *testing.T) {
// given
namespace := "host-operator-" + uuid.Must(uuid.NewV4()).String()[:7]
assets := assets.NewAssets(testusertiers.AssetNames, testusertiers.Asset)
tc, err := newUserTierGenerator(s, nil, namespace, assets)
tc, err := newUserTierGenerator(s, nil, namespace, TestUserTierTemplatesFS, testRoot)
require.NoError(t, err)

for _, tier := range expectedTestTiers {
Expand Down
Loading