Skip to content

Commit

Permalink
refactor: moved to separate module
Browse files Browse the repository at this point in the history
  • Loading branch information
hosekpeter committed Nov 11, 2024
1 parent 9ab9c9c commit 920869a
Show file tree
Hide file tree
Showing 4 changed files with 359 additions and 197 deletions.
90 changes: 90 additions & 0 deletions internal/pkg/project/ignore/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package ignore

import (
"context"
"strings"

"github.com/keboola/keboola-as-code/internal/pkg/filesystem"
"github.com/keboola/keboola-as-code/internal/pkg/state"
"github.com/keboola/keboola-as-code/internal/pkg/utils/errors"
)

const KBCIgnoreFilePath = ".keboola/kbc_ignore"

type File struct {
rawStringPattern string
state *state.Registry
}

func newFile(pattern string, state *state.Registry) *File {
return &File{
rawStringPattern: pattern,
state: state,
}
}

func LoadFile(ctx context.Context, fs filesystem.Fs, state *state.Registry, path string) (*File, error) {
if !fs.Exists(ctx, path) {
return nil, errors.Errorf("ignore file \"%s\" not found", path)
}

content, err := fs.ReadFile(ctx, filesystem.NewFileDef(path))
if err != nil {
return nil, err
}

f := &File{
state: state,
rawStringPattern: content.Content,
}

return f, nil
}

func (f *File) IgnoreConfigsOrRows() error {
return f.applyIgnoredPatterns()
}

func (f *File) parseIgnoredPatterns() []string {
var ignorePatterns []string
lines := strings.Split(f.rawStringPattern, "\n")
for _, line := range lines {
trimmedLine := strings.TrimSpace(line)
// Skip empty lines and comments
if trimmedLine != "" && !strings.HasPrefix(trimmedLine, "#") {
ignorePatterns = append(ignorePatterns, trimmedLine)
}
}

return ignorePatterns
}

// applyIgnorePattern applies a single ignore pattern, marking the appropriate config or row as ignored.
func (f *File) applyIgnorePattern(ignoreConfig string) error {
parts := strings.Split(ignoreConfig, "/")

switch len(parts) {
case 2:
// Ignore config by ID and name.
configID, componentID := parts[1], parts[0]
f.state.IgnoreConfig(configID, componentID)
case 3:
// Ignore specific config row.
configID, rowID := parts[1], parts[2]
f.state.IgnoreConfigRow(configID, rowID)
default:
return errors.Errorf("invalid ignore ignoreConfig format: %s", ignoreConfig)
}

return nil
}

// applyIgnoredPatterns parses the content for ignore patterns and applies them to configurations or rows.
func (f *File) applyIgnoredPatterns() error {
for _, pattern := range f.parseIgnoredPatterns() {
if err := f.applyIgnorePattern(pattern); err != nil {
continue
}
}
return nil
}
242 changes: 242 additions & 0 deletions internal/pkg/project/ignore/file_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
package ignore

import (
"context"
"fmt"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/keboola/keboola-as-code/internal/pkg/filesystem"
"github.com/keboola/keboola-as-code/internal/pkg/filesystem/aferofs"
"github.com/keboola/keboola-as-code/internal/pkg/filesystem/knownpaths"
"github.com/keboola/keboola-as-code/internal/pkg/model"
"github.com/keboola/keboola-as-code/internal/pkg/naming"
"github.com/keboola/keboola-as-code/internal/pkg/state/registry"
)

func Test_loadFile(t *testing.T) {
t.Parallel()
ctx := context.Background()

projectState := newTestRegistry(t)

fs := aferofs.NewMemoryFs()
require.NoError(t, fs.WriteFile(ctx, filesystem.NewRawFile(`foo/bar1`, "keboola.bar/678/34\nkeboola.foo/345")))

file, err := LoadFile(ctx, fs, projectState, "foo/bar1")
require.NoError(t, err)

assert.Equal(t, "keboola.bar/678/34\nkeboola.foo/345", file.rawStringPattern)

assert.NoError(t, file.IgnoreConfigsOrRows())

assert.Len(t, projectState.IgnoredConfigRows(), 1)
assert.Len(t, projectState.IgnoredConfigs(), 1)
assert.Equal(t, projectState.IgnoredConfigRows()[0].ID.String(), "34")
assert.Equal(t, projectState.IgnoredConfigs()[0].ID.String(), "345")
}

func Test_applyIgnoredPatterns(t *testing.T) {
t.Parallel()
projectState := newTestRegistry(t)

type args struct {
pattern string
}

file := &File{
state: projectState,
}

tests := []struct {
name string
args args
wantErr assert.ErrorAssertionFunc
}{
{
name: "empty patterns",
args: args{
pattern: "",
},
wantErr: assert.Error,
},
{
name: "wrong pattern",
args: args{
pattern: "wrong pattern",
},
wantErr: assert.Error,
},
{
name: "too long pattern",
args: args{
pattern: "keboola.bar/687/1234/1234",
},
wantErr: assert.Error,
},
{
name: "short pattern",
args: args{
pattern: "keboola.bar",
},
wantErr: assert.Error,
},
{
name: "correct pattern",
args: args{
pattern: "keboola.bar/687",
},
wantErr: assert.NoError,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
tt.wantErr(t, file.applyIgnorePattern(tt.args.pattern), fmt.Sprintf("applyIgnoredPatterns(%v)", tt.args.pattern))
})
}
}

func Test_parseIgnoredPatterns(t *testing.T) {
t.Parallel()

projectState := newTestRegistry(t)

type args struct {
content string
}
tests := []struct {
name string
args args
want []string
}{
{
name: "with comments",
args: args{
content: "##dataapps\nkeboola.data-apps/12345\n##dataapps2\nkeboola.data-apps/123/rowId123\n##dataaps3\nkeboola.data-apps/12",
},
want: []string{
"keboola.data-apps/12345",
"keboola.data-apps/123/rowId123",
"keboola.data-apps/12",
},
},
{
name: "with empty lines",
args: args{
content: "##dataapps\n\n\n\n\n\nkeboola.data-apps/12345\n\t##dataapps2\nkeboola.data-apps/123\n##dataaps3\nkeboola.data-apps/12",
},
want: []string{
"keboola.data-apps/12345",
"keboola.data-apps/123",
"keboola.data-apps/12",
},
},
{
name: "empty file",
args: args{
content: "\n",
},
want: nil,
},
{
name: "error",
args: args{
content: "##dataapps\n\n\n\n\n\nkeboola.data-apps/12345\n\t##dataapps2\nkeboola.data-apps/123\n##dataaps3\nkeboola.data-apps/12",
},
want: []string{
"keboola.data-apps/12345",
"keboola.data-apps/123",
"keboola.data-apps/12",
},
},
{
name: "empty file",
args: args{
content: "\n",
},
want: nil,
},
}

for _, tt := range tests {
file := newFile(tt.args.content, projectState)
got := file.parseIgnoredPatterns()
assert.Equal(t, tt.want, got)
}
}

func newTestRegistry(t *testing.T) *registry.Registry {
t.Helper()

r := registry.New(knownpaths.NewNop(context.Background()), naming.NewRegistry(), model.NewComponentsMap(nil), model.SortByPath)
// Branch 1
branch1Key := model.BranchKey{ID: 123}
branch1 := &model.BranchState{
BranchManifest: &model.BranchManifest{
BranchKey: branch1Key,
},
Local: &model.Branch{
Name: "Main",
IsDefault: true,
},
}
assert.NoError(t, r.Set(branch1))

// Branch 2
branch2Key := model.BranchKey{ID: 567}
branch2 := &model.BranchState{
BranchManifest: &model.BranchManifest{
BranchKey: branch2Key,
},
Local: &model.Branch{
Name: "Foo Bar Branch",
IsDefault: false,
},
}
assert.NoError(t, r.Set(branch2))

// Config 1
config1Key := model.ConfigKey{BranchID: 123, ComponentID: "keboola.foo", ID: `345`}
config1 := &model.ConfigState{
ConfigManifest: &model.ConfigManifest{ConfigKey: config1Key},
Local: &model.Config{
Name: "Config 1",
},
}
assert.NoError(t, r.Set(config1))

// Config 2
config2Key := model.ConfigKey{BranchID: 123, ComponentID: "keboola.bar", ID: `678`}
config2 := &model.ConfigState{
ConfigManifest: &model.ConfigManifest{ConfigKey: config2Key},
Local: &model.Config{
Name: "Config 2",
},
}
assert.NoError(t, r.Set(config2))

// Config Row 1
row1Key := model.ConfigRowKey{BranchID: 123, ComponentID: "keboola.bar", ConfigID: `678`, ID: `12`}
row1 := &model.ConfigRowState{
ConfigRowManifest: &model.ConfigRowManifest{ConfigRowKey: row1Key},
Local: &model.ConfigRow{
Name: "Config Row 1",
},
}
assert.NoError(t, r.Set(row1))

// Config Row 2
row2Key := model.ConfigRowKey{BranchID: 123, ComponentID: "keboola.bar", ConfigID: `678`, ID: `34`}
row2 := &model.ConfigRowState{
ConfigRowManifest: &model.ConfigRowManifest{ConfigRowKey: row2Key},
Local: &model.ConfigRow{
Name: "Config Row 2",
},
}
assert.NoError(t, r.Set(row2))

return r
}
Loading

0 comments on commit 920869a

Please sign in to comment.