Skip to content
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

Add exclude-regex to config #720

Merged
merged 3 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 2 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ Parameter Descriptions
| `disable-version-string` | :fontawesome-solid-x: | `#!yaml false` | Disable the version string in the generated mock files. |
| `dry-run` | :fontawesome-solid-x: | `#!yaml false` | Print the actions that would be taken, but don't perform the actions. |
| `exclude` | :fontawesome-solid-x: | `#!yaml []` | Specify subpackages to exclude when using `#!yaml recursive: True` |
| `exclude-regex` | :fontawesome-solid-x: | `#!yaml ""` | When set along with `include-regex`, then interfaces which match `include-regex` but also match `exclude-regex` will not be generated. If `all` is set, or if `include-regex` is not set, then `exclude-regex` has no effect. |
| `filename` | :fontawesome-solid-check: | `#!yaml "mock_{{.InterfaceName}}.go"` | The name of the file the mock will reside in. |
| `include-auto-generated` | :fontawesome-solid-x: | `#!yaml true` | Set to `#!yaml false` if you need mockery to skip auto-generated files during its recursive package discovery. When set to `#!yaml true`, mockery includes auto-generated files when determining if a particular directory is an importable package. |
| `include-regex` | :fontawesome-solid-x: | `#!yaml ""` | When set, only interface names that match the expression will be generated. This setting is ignored if `all: True` is specified in the configuration |
| `include-regex` | :fontawesome-solid-x: | `#!yaml ""` | When set, only interface names that match the expression will be generated. This setting is ignored if `all: True` is specified in the configuration. To further refine the interfaces generated, use `exclude-regex`. |
| `inpackage` | :fontawesome-solid-x: | `#!yaml false` | When generating mocks alongside the original interfaces, you must specify `inpackage: True` to inform mockery that the mock is being placed in the same package as the original interface. |
| `mockname` | :fontawesome-solid-check: | `#!yaml "Mock{{.InterfaceName}}"` | The name of the generated mock. |
| `outpkg` | :fontawesome-solid-check: | `#!yaml "{{.PackageName}}"` | Use `outpkg` to specify the package name of the generated mocks. |
Expand Down
15 changes: 14 additions & 1 deletion docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,21 @@ packages:
include-regex: ".*Client"
```

To further refine matched interfaces, you can also use `exclude-regex`. If an interface matches both `include-regex` and `exclude-regex` then it will not be generated. For example, to generate all interfaces except those ending in `Func`:

```yaml
packages:
github.com/user/project:
config:
recursive: true
include-regex: ".*"
exclude-regex: ".*Func"
```

You can only use `exclude-regex` with `include-regex`. If set by itself, `exclude-regex` has no effect.

??? note "all: true"
Using `all: true` will override `include-regex` and issue a warning.
Using `all: true` will override `include-regex` (and `exclude-regex`) and issue a warning.

Mock Constructors
-----------------
Expand Down
27 changes: 23 additions & 4 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type Config struct {
DisableConfigSearch bool `mapstructure:"disable-config-search"`
DisableVersionString bool `mapstructure:"disable-version-string"`
DryRun bool `mapstructure:"dry-run"`
ExcludeRegex string `mapstructure:"exclude-regex"`
Exported bool `mapstructure:"exported"`
FileName string `mapstructure:"filename"`
IncludeAutoGenerated bool `mapstructure:"include-auto-generated"`
Expand Down Expand Up @@ -271,19 +272,37 @@ func (c *Config) ShouldGenerateInterface(ctx context.Context, packageName, inter
}
_, interfaceExists := interfacesSection[interfaceName]

var matchedByRegex bool
matchedByRegex := false
if pkgConfig.IncludeRegex != "" {
if pkgConfig.All {
log := zerolog.Ctx(ctx)
log.Warn().Msg("interface config has both `all` and `include-regex` set. `include-regex` will be ignored")
log.Warn().Msg("interface config has both `all` and `include-regex` set: `include-regex` will be ignored")
} else {
matchedByRegex, err = regexp.MatchString(pkgConfig.IncludeRegex, interfaceName)
if err != nil {
return false, err
return false, fmt.Errorf("evaluating `include-regex`: %w", err)
}
}
}
return pkgConfig.All || interfaceExists || matchedByRegex, nil
excludedByRegex := false
if pkgConfig.ExcludeRegex != "" {
if pkgConfig.All {
log := zerolog.Ctx(ctx)
log.Warn().Msg("interface config has both `all` and `exclude-regex` set: `exclude-regex` will be ignored")
} else if pkgConfig.IncludeRegex == "" {
log := zerolog.Ctx(ctx)
log.Warn().Msg("interface config has `exclude-regex` set but not `include-regex`: `exclude-regex` will be ignored")
} else {
excludedByRegex, err = regexp.MatchString(pkgConfig.ExcludeRegex, interfaceName)
if err != nil {
return false, fmt.Errorf("evaluating `exclude-regex`: %w", err)
}
if excludedByRegex {
matchedByRegex = false
}
kbolino marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say we can reorganize this code. We should have a separate section that logs the warnings like:

if pkgConfig.All {
    if pkgConfig.IncludeRegex != "" {
        log.Warn().Msg("interface config has both `all` and `include-regex` set: `include-regex` will be ignored")
    }
    if pkgConfig.ExcludeRegex != "" {
        log.Warn().Msg("interface config has both `all` and `exclude-regex` set: `exclude-regex` will be ignored")
    }
    return true
}

Then populate the matchedBy/excludedBy variables if pkgConfig.All == true

var matchedByRegex, excludedByRegex bool
if pkgConfig.IncludeRegex != "" {
    // do matching
}
if pkgConfig.ExcludeRegex != "" {
    // do matching
}
return interfaceExists || (matchedByRegex && !excludedByRegex)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have taken a few liberties to reduce nesting, LMK if it needs more work

}
}
return pkgConfig.All || interfaceExists || (matchedByRegex && !excludedByRegex), nil
}

func (c *Config) getInterfacesSection(ctx context.Context, packageName string) (map[string]any, error) {
Expand Down
91 changes: 88 additions & 3 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ func TestConfig_ShouldGenerateInterface(t *testing.T) {
want: true,
},
{
name: "should generate using included-regex",
name: "should generate using include-regex",
c: &Config{
Packages: map[string]interface{}{
"some_package": map[string]interface{}{
Expand All @@ -622,7 +622,7 @@ func TestConfig_ShouldGenerateInterface(t *testing.T) {
want: true,
},
{
name: "should generate when using all and included-regex doesn't match",
name: "should generate when using all and include-regex doesn't match",
c: &Config{
Packages: map[string]interface{}{
"some_package": map[string]interface{}{
Expand All @@ -636,7 +636,7 @@ func TestConfig_ShouldGenerateInterface(t *testing.T) {
want: true,
},
{
name: "should not generate when included-regex doesn't match",
name: "should not generate when include-regex doesn't match",
c: &Config{
Packages: map[string]interface{}{
"some_package": map[string]interface{}{
Expand All @@ -648,6 +648,91 @@ func TestConfig_ShouldGenerateInterface(t *testing.T) {
},
want: false,
},
{
name: "should not generate when include-regex and exclude-regex both match",
c: &Config{
Packages: map[string]interface{}{
"some_package": map[string]interface{}{
"config": map[string]interface{}{
"include-regex": ".*Interface",
"exclude-regex": "Some.*",
},
},
},
},
want: false,
},
{
name: "should generate when include-regex matches but not exclude-regex",
c: &Config{
Packages: map[string]interface{}{
"some_package": map[string]interface{}{
"config": map[string]interface{}{
"include-regex": ".*Interface",
"exclude-regex": "Foo.*",
},
},
},
},
want: true,
},
{
name: "should not generate when neither include-regex nor exclude-regex match",
c: &Config{
Packages: map[string]interface{}{
"some_package": map[string]interface{}{
"config": map[string]interface{}{
"include-regex": ".*XInterface",
"exclude-regex": "Foo.*",
},
},
},
},
want: false,
},
{
name: "should not generate when exclude-regex doesn't match but include-regex isn't set",
c: &Config{
Packages: map[string]interface{}{
"some_package": map[string]interface{}{
"config": map[string]interface{}{
"exclude-regex": "Foo.*",
},
},
},
},
want: false,
},
{
name: "should generate when using all and exclude-regex matches",
c: &Config{
Packages: map[string]interface{}{
"some_package": map[string]interface{}{
"config": map[string]interface{}{
"all": true,
"exclude-regex": ".*Interface",
},
},
},
},
want: true,
},
{
name: "should generate when interface is selected and exclude-regex matches",
c: &Config{
Packages: map[string]interface{}{
"some_package": map[string]interface{}{
"interfaces": map[string]interface{}{
"SomeInterface": struct{}{},
},
"config": map[string]interface{}{
"exclude-regex": ".*Interface",
},
},
},
},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
Loading