Skip to content

Commit b9ac16f

Browse files
authored
Merge pull request #71 from mxlint/feat/filter
Feat/filter
2 parents 88aaf8f + 05fe404 commit b9ac16f

6 files changed

Lines changed: 123 additions & 12 deletions

File tree

main.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ func main() {
2626
mode, _ := cmd.Flags().GetString("mode")
2727
verbose, _ := cmd.Flags().GetBool("verbose")
2828
appstore, _ := cmd.Flags().GetBool("appstore")
29+
filter, _ := cmd.Flags().GetString("filter")
2930

3031
log := logrus.New()
3132
if verbose {
@@ -35,13 +36,14 @@ func main() {
3536
}
3637

3738
mpr.SetLogger(log)
38-
mpr.ExportModel(inputDirectory, outputDirectory, raw, mode, appstore)
39+
mpr.ExportModel(inputDirectory, outputDirectory, raw, mode, appstore, filter)
3940
},
4041
}
4142

4243
cmdExportModel.Flags().StringP("input", "i", ".", "Path to directory or mpr file to export. If it's a directory, all mpr files will be exported")
4344
cmdExportModel.Flags().StringP("output", "o", "modelsource", "Path to directory to write the yaml files. If it doesn't exist, it will be created")
4445
cmdExportModel.Flags().StringP("mode", "m", "basic", "Export mode. Valid options: basic, advanced")
46+
cmdExportModel.Flags().StringP("filter", "f", "", "Regex pattern to filter units by name. Only units with names matching the pattern will be exported")
4547
cmdExportModel.Flags().Bool("raw", false, "If set, the output yaml will include all attributes as they are in the model. Otherwise, only the relevant attributes are included. You should never need this. Only useful when you are developing new functionalities for this tool.")
4648
cmdExportModel.Flags().Bool("appstore", false, "If set, appstore modules will be included in the output")
4749
cmdExportModel.Flags().Bool("verbose", false, "Turn on for debug logs")

mpr/microflow_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313

1414
func TestMPRMicroflow(t *testing.T) {
1515
t.Run("microflow-simple", func(t *testing.T) {
16-
if err := exportUnits("./../resources/app-mpr-v1/App.mpr", "./../tmp", true, "advanced"); err != nil {
16+
if err := exportUnits("./../resources/app-mpr-v1/App.mpr", "./../tmp", true, "advanced", ""); err != nil {
1717
t.Errorf("Failed to export units from MPR file")
1818
}
1919

@@ -42,7 +42,7 @@ func TestMPRMicroflow(t *testing.T) {
4242
}
4343
})
4444
t.Run("microflow-with-split", func(t *testing.T) {
45-
if err := exportUnits("./../resources/app-mpr-v1/App.mpr", "./../tmp", true, "advanced"); err != nil {
45+
if err := exportUnits("./../resources/app-mpr-v1/App.mpr", "./../tmp", true, "advanced", ""); err != nil {
4646
t.Errorf("Failed to export units from MPR file")
4747
}
4848

@@ -71,7 +71,7 @@ func TestMPRMicroflow(t *testing.T) {
7171
}
7272
})
7373
t.Run("microflow-split-then-merge", func(t *testing.T) {
74-
if err := exportUnits("./../resources/app-mpr-v1/App.mpr", "./../tmp", true, "advanced"); err != nil {
74+
if err := exportUnits("./../resources/app-mpr-v1/App.mpr", "./../tmp", true, "advanced", ""); err != nil {
7575
t.Errorf("Failed to export units from MPR file")
7676
}
7777

mpr/mpr.go

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"io"
99
"os"
1010
"path/filepath"
11+
"regexp"
1112
"strings"
1213

1314
"gopkg.in/yaml.v3"
@@ -30,7 +31,7 @@ const (
3031
MaxComponentLength = 100
3132
)
3233

33-
func ExportModel(inputDirectory string, outputDirectory string, raw bool, mode string, appstore bool) error {
34+
func ExportModel(inputDirectory string, outputDirectory string, raw bool, mode string, appstore bool, filter string) error {
3435

3536
// create tmp directory in user tmp directory
3637
tmpDir := filepath.Join(os.TempDir(), "mxlint")
@@ -63,8 +64,10 @@ func ExportModel(inputDirectory string, outputDirectory string, raw bool, mode s
6364
return fmt.Errorf("error exporting metadata: %v", err)
6465
}
6566

66-
if err := exportUnits(inputDirectory, tmpDir, raw, mode); err != nil {
67-
return fmt.Errorf("error exporting units: %v", err)
67+
if filter != "^Metadata$" {
68+
if err := exportUnits(inputDirectory, tmpDir, raw, mode, filter); err != nil {
69+
return fmt.Errorf("error exporting units: %v", err)
70+
}
6871
}
6972

7073
// remove output directory if it exists
@@ -452,7 +455,7 @@ func getMxDocuments(units []MxUnit, folders []MxFolder, mode string) ([]MxDocume
452455
return documents, nil
453456
}
454457

455-
func exportUnits(inputDirectory string, outputDirectory string, raw bool, mode string) error {
458+
func exportUnits(inputDirectory string, outputDirectory string, raw bool, mode string, filter string) error {
456459
log.Debugf("Exporting units from %s to %s", inputDirectory, outputDirectory)
457460

458461
units, err := getMxUnits(inputDirectory)
@@ -469,7 +472,25 @@ func exportUnits(inputDirectory string, outputDirectory string, raw bool, mode s
469472
return fmt.Errorf("error getting documents: %v", err)
470473
}
471474

475+
// Compile the filter regex if provided
476+
var filterRegex *regexp.Regexp
477+
if filter != "" {
478+
filterRegex, err = regexp.Compile(filter)
479+
if err != nil {
480+
return fmt.Errorf("invalid filter regex pattern: %v", err)
481+
}
482+
log.Infof("Applying filter: %s", filter)
483+
}
484+
485+
exportedCount := 0
472486
for _, document := range documents {
487+
// Apply filter if provided
488+
if filterRegex != nil {
489+
if !filterRegex.MatchString(document.Name) {
490+
log.Debugf("Skipping document '%s' (does not match filter)", document.Name)
491+
continue
492+
}
493+
}
473494
// write document
474495
// Sanitize the document path to handle invalid characters
475496
sanitizedPath := sanitizePath(document.Path)
@@ -510,6 +531,11 @@ func exportUnits(inputDirectory string, outputDirectory string, raw bool, mode s
510531
log.Errorf("Error writing file: %v", err)
511532
return err
512533
}
534+
exportedCount++
535+
}
536+
537+
if filterRegex != nil {
538+
log.Infof("Exported %d documents matching filter (out of %d total)", exportedCount, len(documents))
513539
}
514540

515541
return nil

mpr/mpr_v1_test.go

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func TestMPRMetadata(t *testing.T) {
4242

4343
func TestMPRUnits(t *testing.T) {
4444
t.Run("single-mpr", func(t *testing.T) {
45-
if err := exportUnits("./../resources/app-mpr-v1", "./../tmp", false, "basic"); err != nil {
45+
if err := exportUnits("./../resources/app-mpr-v1", "./../tmp", false, "basic", ""); err != nil {
4646
t.Errorf("Failed to export units from MPR file")
4747
}
4848
})
@@ -51,7 +51,7 @@ func TestMPRUnits(t *testing.T) {
5151
func TestIDAttributesExclusion(t *testing.T) {
5252
t.Run("verify-id-attributes-excluded", func(t *testing.T) {
5353
// Export units with ID attributes excluded
54-
if err := exportUnits("./../resources/app-mpr-v1", "./../tmp", false, "basic"); err != nil {
54+
if err := exportUnits("./../resources/app-mpr-v1", "./../tmp", false, "basic", ""); err != nil {
5555
t.Errorf("Failed to export units from MPR file: %v", err)
5656
return
5757
}
@@ -98,3 +98,86 @@ func TestIDAttributesExclusion(t *testing.T) {
9898
}
9999
})
100100
}
101+
102+
func TestFilterMetadataOnly(t *testing.T) {
103+
t.Run("filter-metadata-exact-match", func(t *testing.T) {
104+
// Clean up test directory
105+
testDir := "./../tmp-filter-metadata"
106+
os.RemoveAll(testDir)
107+
defer os.RemoveAll(testDir)
108+
109+
// Export with filter ^Metadata$
110+
// According to the code, when filter is "^Metadata$", only metadata is exported, no units
111+
if err := ExportModel("./../resources/app-mpr-v1", testDir, false, "basic", false, "^Metadata$"); err != nil {
112+
t.Errorf("Failed to export with Metadata filter: %v", err)
113+
return
114+
}
115+
116+
// Check that Metadata.yaml exists
117+
metadataPath := filepath.Join(testDir, "Metadata.yaml")
118+
if _, err := os.Stat(metadataPath); os.IsNotExist(err) {
119+
t.Errorf("Metadata.yaml was not created")
120+
return
121+
}
122+
123+
// Check that no other files/directories were created (since filter is ^Metadata$ and units are skipped)
124+
entries, err := os.ReadDir(testDir)
125+
if err != nil {
126+
t.Errorf("Failed to read test directory: %v", err)
127+
return
128+
}
129+
130+
// Should only have Metadata.yaml
131+
if len(entries) != 1 {
132+
t.Errorf("Expected only Metadata.yaml, but found %d entries", len(entries))
133+
return
134+
}
135+
136+
if entries[0].Name() != "Metadata.yaml" {
137+
t.Errorf("Expected Metadata.yaml, but found %s", entries[0].Name())
138+
}
139+
})
140+
}
141+
142+
func TestFilterConstantPattern(t *testing.T) {
143+
t.Run("filter-constant-pattern", func(t *testing.T) {
144+
// Clean up test directory
145+
testDir := "./../tmp-filter-constant"
146+
os.RemoveAll(testDir)
147+
defer os.RemoveAll(testDir)
148+
149+
// Export with filter ^Constant.*
150+
// This pattern won't match any documents in the test data, so we should get only metadata
151+
if err := ExportModel("./../resources/app-mpr-v1", testDir, false, "basic", false, "^Constant.*"); err != nil {
152+
t.Errorf("Failed to export with Constant filter: %v", err)
153+
return
154+
}
155+
156+
// Check that Metadata.yaml exists (always exported)
157+
metadataPath := filepath.Join(testDir, "Metadata.yaml")
158+
if _, err := os.Stat(metadataPath); os.IsNotExist(err) {
159+
t.Errorf("Metadata.yaml was not created")
160+
return
161+
}
162+
163+
// Check that no module directories were created (since no documents match the filter)
164+
entries, err := os.ReadDir(testDir)
165+
if err != nil {
166+
t.Errorf("Failed to read test directory: %v", err)
167+
return
168+
}
169+
170+
// Should only have Metadata.yaml since no documents match ^Constant.*
171+
if len(entries) != 1 {
172+
t.Errorf("Expected only Metadata.yaml when no documents match filter, but found %d entries", len(entries))
173+
for _, entry := range entries {
174+
t.Logf("Found entry: %s", entry.Name())
175+
}
176+
return
177+
}
178+
179+
if entries[0].Name() != "Metadata.yaml" {
180+
t.Errorf("Expected Metadata.yaml, but found %s", entries[0].Name())
181+
}
182+
})
183+
}

mpr/mpr_v2_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func TestMPRV2Metadata(t *testing.T) {
3939

4040
func TestMPRV2Units(t *testing.T) {
4141
t.Run("single-mpr", func(t *testing.T) {
42-
if err := exportUnits("./../resources/app-mpr-v2", "./../tmp", false, "basic"); err != nil {
42+
if err := exportUnits("./../resources/app-mpr-v2", "./../tmp", false, "basic", ""); err != nil {
4343
t.Errorf("Failed to export units from MPR file")
4444
}
4545
})

serve/serve.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ func runServe(cmd *cobra.Command, args []string) {
189189
}()
190190

191191
log.Infof("Running export-model and lint")
192-
err := mpr.ExportModel(inputDirectory, outputDirectory, false, mode, false)
192+
err := mpr.ExportModel(inputDirectory, outputDirectory, false, mode, false, "")
193193
if err != nil {
194194
log.Warningf("Export failed: %s", err)
195195
resultMutex.Lock()

0 commit comments

Comments
 (0)