mirror of
https://github.com/foomo/squadron.git
synced 2025-10-16 12:35:42 +00:00
feat: add tags
This commit is contained in:
parent
c0c52b85d9
commit
bede368045
@ -5,6 +5,7 @@ squadron:
|
||||
checkout:
|
||||
backend:
|
||||
chart: <% env "PROJECT_ROOT" %>/../common/charts/backend
|
||||
tags: [ "backend" ]
|
||||
builds:
|
||||
default:
|
||||
tag: <% .Global.docker.tag | quote %>
|
||||
|
||||
@ -5,6 +5,7 @@ squadron:
|
||||
checkout:
|
||||
frontend:
|
||||
chart: <% env "PROJECT_ROOT" %>/../common/charts/frontend
|
||||
tags: [ "frontend" ]
|
||||
builds:
|
||||
default:
|
||||
tag: "<% .Global.docker.tag %>"
|
||||
|
||||
@ -5,6 +5,7 @@ squadron:
|
||||
storefinder:
|
||||
backend:
|
||||
chart: <% env "PROJECT_ROOT" %>/../common/charts/backend
|
||||
tags: [ "backend" ]
|
||||
builds:
|
||||
default:
|
||||
tag: <% .Global.docker.tag | quote %>
|
||||
|
||||
@ -5,6 +5,7 @@ squadron:
|
||||
storefinder:
|
||||
frontend:
|
||||
chart: <% env "PROJECT_ROOT" %>/../common/charts/frontend
|
||||
tags: [ "frontend" ]
|
||||
builds:
|
||||
default:
|
||||
tag: "<% .Global.docker.tag %>"
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
func init() {
|
||||
buildCmd.Flags().BoolVarP(&flagPush, "push", "p", false, "pushes built squadron units to the registry")
|
||||
buildCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel")
|
||||
buildCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)")
|
||||
buildCmd.Flags().StringSliceVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args")
|
||||
buildCmd.Flags().StringSliceVar(&flagPushArgs, "push-args", nil, "additional docker push args")
|
||||
}
|
||||
@ -25,7 +26,7 @@ var buildCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
squadronName, unitNames := parseSquadronAndUnitNames(args)
|
||||
if err := sq.FilterConfig(squadronName, unitNames); err != nil {
|
||||
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -3,14 +3,14 @@ package actions
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/foomo/squadron"
|
||||
"github.com/foomo/squadron/internal/util"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/foomo/squadron"
|
||||
)
|
||||
|
||||
func init() {
|
||||
configCmd.Flags().BoolVar(&flagNoRender, "no-render", false, "don't render the config template")
|
||||
configCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)")
|
||||
}
|
||||
|
||||
var configCmd = &cobra.Command{
|
||||
@ -26,7 +26,7 @@ var configCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
squadronName, unitNames := parseSquadronAndUnitNames(args)
|
||||
if err := sq.FilterConfig(squadronName, unitNames); err != nil {
|
||||
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
diffCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace")
|
||||
diffCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})")
|
||||
diffCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel")
|
||||
}
|
||||
|
||||
|
||||
@ -8,7 +8,8 @@ import (
|
||||
|
||||
func init() {
|
||||
downCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel")
|
||||
downCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "Specifies the namespace")
|
||||
downCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})")
|
||||
downCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)")
|
||||
}
|
||||
|
||||
var downCmd = &cobra.Command{
|
||||
@ -26,7 +27,7 @@ var downCmd = &cobra.Command{
|
||||
args, helmArgs := parseExtraArgs(args)
|
||||
|
||||
squadronName, unitNames := parseSquadronAndUnitNames(args)
|
||||
if err := sq.FilterConfig(squadronName, unitNames); err != nil {
|
||||
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,10 @@ import (
|
||||
|
||||
var flagPrefixSquadron bool
|
||||
|
||||
func init() {
|
||||
listCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)")
|
||||
}
|
||||
|
||||
var listCmd = &cobra.Command{
|
||||
Use: "list [SQUADRON]",
|
||||
Short: "list squadron units",
|
||||
@ -23,7 +27,7 @@ var listCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
squadronName, unitNames := parseSquadronAndUnitNames(args)
|
||||
if err := sq.FilterConfig(squadronName, unitNames); err != nil {
|
||||
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -6,11 +6,12 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
pushCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace")
|
||||
pushCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})")
|
||||
pushCmd.Flags().BoolVarP(&flagBuild, "build", "b", false, "builds or rebuilds units")
|
||||
pushCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel")
|
||||
pushCmd.Flags().StringSliceVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args")
|
||||
pushCmd.Flags().StringSliceVar(&flagPushArgs, "push-args", nil, "additional docker push args")
|
||||
pushCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)")
|
||||
}
|
||||
|
||||
var pushCmd = &cobra.Command{
|
||||
@ -25,7 +26,7 @@ var pushCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
squadronName, unitNames := parseSquadronAndUnitNames(args)
|
||||
if err := sq.FilterConfig(squadronName, unitNames); err != nil {
|
||||
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -8,8 +8,9 @@ import (
|
||||
|
||||
func init() {
|
||||
rollbackCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel")
|
||||
rollbackCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace")
|
||||
rollbackCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})")
|
||||
rollbackCmd.Flags().StringVarP(&flagRevision, "revision", "r", "", "specifies the revision to roll back to")
|
||||
rollbackCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)")
|
||||
}
|
||||
|
||||
var rollbackCmd = &cobra.Command{
|
||||
@ -26,7 +27,7 @@ var rollbackCmd = &cobra.Command{
|
||||
args, helmArgs := parseExtraArgs(args)
|
||||
|
||||
squadronName, unitNames := parseSquadronAndUnitNames(args)
|
||||
if err := sq.FilterConfig(squadronName, unitNames); err != nil {
|
||||
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -46,6 +46,7 @@ var (
|
||||
flagParallel int
|
||||
flagBuildArgs []string
|
||||
flagPushArgs []string
|
||||
flagTags []string
|
||||
flagDiff bool
|
||||
flagFiles []string
|
||||
)
|
||||
|
||||
@ -8,7 +8,8 @@ import (
|
||||
|
||||
func init() {
|
||||
statusCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel")
|
||||
statusCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace")
|
||||
statusCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})")
|
||||
statusCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)")
|
||||
}
|
||||
|
||||
var statusCmd = &cobra.Command{
|
||||
@ -25,7 +26,7 @@ var statusCmd = &cobra.Command{
|
||||
args, helmArgs := parseExtraArgs(args)
|
||||
|
||||
squadronName, unitNames := parseSquadronAndUnitNames(args)
|
||||
if err := sq.FilterConfig(squadronName, unitNames); err != nil {
|
||||
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,8 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
templateCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace")
|
||||
templateCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})")
|
||||
templateCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)")
|
||||
}
|
||||
|
||||
var templateCmd = &cobra.Command{
|
||||
@ -27,7 +28,7 @@ var templateCmd = &cobra.Command{
|
||||
args, helmArgs := parseExtraArgs(args)
|
||||
|
||||
squadronName, unitNames := parseSquadronAndUnitNames(args)
|
||||
if err := sq.FilterConfig(squadronName, unitNames); err != nil {
|
||||
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -10,12 +10,13 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
upCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "specifies the namespace")
|
||||
upCmd.Flags().StringVarP(&flagNamespace, "namespace", "n", "default", "set the namespace name or template (default, squadron-{{.Squadron}}-{{.Unit}})")
|
||||
upCmd.Flags().BoolVarP(&flagBuild, "build", "b", false, "builds or rebuilds units")
|
||||
upCmd.Flags().BoolVarP(&flagPush, "push", "p", false, "pushes units to the registry")
|
||||
upCmd.Flags().IntVar(&flagParallel, "parallel", 1, "run command in parallel")
|
||||
upCmd.Flags().StringSliceVar(&flagBuildArgs, "build-args", nil, "additional docker buildx build args")
|
||||
upCmd.Flags().StringSliceVar(&flagPushArgs, "push-args", nil, "additional docker push args")
|
||||
upCmd.Flags().StringSliceVar(&flagTags, "tags", nil, "list of tags to include or exclude (can specify multiple or separate values with commas: tag1,tag2,-tag3)")
|
||||
}
|
||||
|
||||
var upCmd = &cobra.Command{
|
||||
@ -32,7 +33,7 @@ var upCmd = &cobra.Command{
|
||||
args, helmArgs := parseExtraArgs(args)
|
||||
|
||||
squadronName, unitNames := parseSquadronAndUnitNames(args)
|
||||
if err := sq.FilterConfig(squadronName, unitNames); err != nil {
|
||||
if err := sq.FilterConfig(squadronName, unitNames, flagTags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -4,10 +4,9 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/foomo/squadron/internal/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/foomo/squadron/internal/util"
|
||||
)
|
||||
|
||||
type Build struct {
|
||||
|
||||
@ -80,6 +80,15 @@ func (m Map[T]) Filter(keys ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Map[T]) FilterFn(handler func(key string, value T) bool) error {
|
||||
for key, value := range m {
|
||||
if !handler(key, value) {
|
||||
delete(m, key)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Map[T]) Iterate(handler func(key string, value T) error) error {
|
||||
if len(m) == 0 {
|
||||
return nil
|
||||
|
||||
3
internal/config/tag.go
Normal file
3
internal/config/tag.go
Normal file
@ -0,0 +1,3 @@
|
||||
package config
|
||||
|
||||
type Tag string
|
||||
@ -14,6 +14,7 @@ import (
|
||||
|
||||
type Unit struct {
|
||||
Chart helm.Dependency `yaml:"chart,omitempty"`
|
||||
Tags []Tag `yaml:"tags,omitempty"`
|
||||
Builds map[string]Build `yaml:"builds,omitempty"`
|
||||
Values map[string]interface{} `yaml:"values,omitempty"`
|
||||
}
|
||||
|
||||
34
squadron.go
34
squadron.go
@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"slices"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
@ -102,13 +103,11 @@ func (sq *Squadron) MergeConfigFiles() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sq *Squadron) FilterConfig(squadron string, units []string) error {
|
||||
if len(squadron) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := sq.Config().Squadrons.Filter(squadron); err != nil {
|
||||
return err
|
||||
func (sq *Squadron) FilterConfig(squadron string, units, tags []string) error {
|
||||
if len(squadron) > 0 {
|
||||
if err := sq.Config().Squadrons.Filter(squadron); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(squadron) > 0 && len(units) > 0 {
|
||||
@ -117,6 +116,27 @@ func (sq *Squadron) FilterConfig(squadron string, units []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
if len(tags) > 0 {
|
||||
if err := sq.Config().Squadrons.Iterate(func(key string, value config.Map[*config.Unit]) error {
|
||||
return value.FilterFn(func(k string, v *config.Unit) bool {
|
||||
for _, tag := range tags {
|
||||
if strings.HasPrefix(tag, "-") {
|
||||
if slices.Contains(v.Tags, config.Tag(strings.TrimPrefix(tag, "-"))) {
|
||||
return false
|
||||
}
|
||||
} else if !slices.Contains(v.Tags, config.Tag(tag)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
sq.c.Trim()
|
||||
|
||||
value, err := yamlv2.Marshal(sq.c)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -9,15 +9,20 @@ import (
|
||||
"github.com/foomo/squadron"
|
||||
"github.com/foomo/squadron/internal/testutils"
|
||||
"github.com/foomo/squadron/internal/util"
|
||||
"github.com/pterm/pterm"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestConfigSimpleSnapshot(t *testing.T) {
|
||||
pterm.EnableDebugMessages()
|
||||
require.NoError(t, os.Setenv("PROJECT_ROOT", "."))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
files []string
|
||||
squadron string
|
||||
units []string
|
||||
tags []string
|
||||
}{
|
||||
{
|
||||
name: "blank",
|
||||
@ -39,21 +44,25 @@ func TestConfigSimpleSnapshot(t *testing.T) {
|
||||
name: "template",
|
||||
files: []string{"squadron.yaml"},
|
||||
},
|
||||
{
|
||||
name: "tags",
|
||||
tags: []string{"backend", "-skip"},
|
||||
files: []string{"squadron.yaml"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(tt *testing.T) {
|
||||
config(tt, test.name, test.files, test.squadron, test.units)
|
||||
config(tt, test.name, test.files, test.squadron, test.units, test.tags)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func config(t *testing.T, name string, files []string, squadronName string, unitNames []string) {
|
||||
func config(t *testing.T, name string, files []string, squadronName string, unitNames, tags []string) {
|
||||
t.Helper()
|
||||
var cwd string
|
||||
ctx := context.TODO()
|
||||
require.NoError(t, util.ValidatePath(".", &cwd))
|
||||
require.NoError(t, os.Setenv("PROJECT_ROOT", "."))
|
||||
|
||||
for i, file := range files {
|
||||
files[i] = path.Join("testdata", name, file)
|
||||
@ -65,7 +74,7 @@ func config(t *testing.T, name string, files []string, squadronName string, unit
|
||||
}
|
||||
|
||||
{
|
||||
require.NoError(t, sq.FilterConfig(squadronName, unitNames), "failed to filter config")
|
||||
require.NoError(t, sq.FilterConfig(squadronName, unitNames, tags), "failed to filter config")
|
||||
testutils.Snapshot(t, path.Join("testdata", name, "snapshop-config-norender.yaml"), sq.ConfigYAML())
|
||||
}
|
||||
|
||||
|
||||
14
testdata/tags/snapshop-config-norender.yaml
vendored
Normal file
14
testdata/tags/snapshop-config-norender.yaml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
version: "2.0"
|
||||
squadron:
|
||||
checkout:
|
||||
backend:
|
||||
chart:
|
||||
name: backend
|
||||
repository: file://<% env "PROJECT_ROOT" %>/_examples/common/charts/backend
|
||||
version: 0.0.1
|
||||
tags:
|
||||
- backend
|
||||
values:
|
||||
image:
|
||||
repository: nginx
|
||||
tag: latest
|
||||
14
testdata/tags/snapshop-config.yaml
vendored
Normal file
14
testdata/tags/snapshop-config.yaml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
version: "2.0"
|
||||
squadron:
|
||||
checkout:
|
||||
backend:
|
||||
chart:
|
||||
name: backend
|
||||
repository: file://./_examples/common/charts/backend
|
||||
version: 0.0.1
|
||||
tags:
|
||||
- backend
|
||||
values:
|
||||
image:
|
||||
repository: nginx
|
||||
tag: latest
|
||||
49
testdata/tags/snapshop-template.yaml
vendored
Normal file
49
testdata/tags/snapshop-template.yaml
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
---
|
||||
# Source: backend/templates/service.yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: backend
|
||||
labels:
|
||||
app.kubernetes.io/name: backend
|
||||
app.kubernetes.io/component: backend
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
helm.sh/chart: backend-0.0.1
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app.kubernetes.io/name: backend
|
||||
app.kubernetes.io/component: backend
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
---
|
||||
# Source: backend/templates/deployment.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: backend
|
||||
labels:
|
||||
app.kubernetes.io/name: backend
|
||||
app.kubernetes.io/component: backend
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
helm.sh/chart: backend-0.0.1
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: backend
|
||||
app.kubernetes.io/component: backend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: backend
|
||||
app.kubernetes.io/component: backend
|
||||
spec:
|
||||
containers:
|
||||
- name: backend
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- name: http
|
||||
protocol: TCP
|
||||
containerPort: 80
|
||||
33
testdata/tags/squadron.yaml
vendored
Normal file
33
testdata/tags/squadron.yaml
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
version: "2.0"
|
||||
|
||||
squadron:
|
||||
storefinder:
|
||||
frontend:
|
||||
chart: <% env "PROJECT_ROOT" %>/_examples/common/charts/frontend
|
||||
tags: ["frontend"]
|
||||
values:
|
||||
image:
|
||||
tag: latest
|
||||
repository: nginx
|
||||
backend:
|
||||
chart: <% env "PROJECT_ROOT" %>/_examples/common/charts/backend
|
||||
tags: ["backend", "skip"]
|
||||
values:
|
||||
image:
|
||||
tag: latest
|
||||
repository: nginx
|
||||
checkout:
|
||||
frontend:
|
||||
chart: <% env "PROJECT_ROOT" %>/_examples/common/charts/frontend
|
||||
tags: ["frontend"]
|
||||
values:
|
||||
image:
|
||||
tag: latest
|
||||
repository: nginx
|
||||
backend:
|
||||
chart: <% env "PROJECT_ROOT" %>/_examples/common/charts/backend
|
||||
tags: ["backend"]
|
||||
values:
|
||||
image:
|
||||
tag: latest
|
||||
repository: nginx
|
||||
Loading…
Reference in New Issue
Block a user