Skip to content

Commit

Permalink
Merge pull request #668 from LandonTClipp/deprecation
Browse files Browse the repository at this point in the history
Add deprecation notice for old config style
  • Loading branch information
LandonTClipp authored Jul 9, 2023
2 parents 7a91185 + a43101b commit 7696d20
Show file tree
Hide file tree
Showing 8 changed files with 345 additions and 259 deletions.
23 changes: 6 additions & 17 deletions cmd/mockery.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,12 +235,6 @@ func (r *RootApp) Run() error {
if err != nil {
return fmt.Errorf("failed to get package from config: %w", err)
}
warnBeta(
ctx,
"use of the 'packages' config variable is currently in a beta state. Use at your own risk.",
map[string]any{
"discussion": "https://github.com/vektra/mockery/discussions/549",
})
parser := pkg.NewParser(buildTags)

if err := parser.ParsePackages(ctx, configuredPackages); err != nil {
Expand Down Expand Up @@ -311,13 +305,12 @@ func (r *RootApp) Run() error {
log.Fatal().Msgf("Use --name to specify the name of the interface or --all for all interfaces found")
}

infoDiscussion(
warnDeprecated(
ctx,
"dynamic walking of project is being considered for removal "+
"in v3. Please provide your feedback at the linked discussion.",
"use of the packages config will be the only way to generate mocks in v3. Please migrate your config to use the packages feature.",
map[string]any{
"pr": "https://github.com/vektra/mockery/pull/548",
"discussion": "https://github.com/vektra/mockery/discussions/549",
"url": logging.DocsURL("/features/#packages-configuration"),
"migration": logging.DocsURL("/migrating_to_packages/"),
})

if r.Config.Profile != "" {
Expand Down Expand Up @@ -422,10 +415,6 @@ func info(ctx context.Context, prefix string, message string, fields map[string]
event.Msgf("%s: %s", prefix, message)
}

func infoDiscussion(ctx context.Context, message string, fields map[string]any) {
info(ctx, "DISCUSSION", message, fields)
}

func warnBeta(ctx context.Context, message string, fields map[string]any) {
warn(ctx, "BETA FEATURE", message, fields)
func warnDeprecated(ctx context.Context, message string, fields map[string]any) {
warn(ctx, "DEPRECATION", message, fields)
}
306 changes: 208 additions & 98 deletions docs/configuration.md

Large diffs are not rendered by default.

30 changes: 27 additions & 3 deletions docs/examples.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
Examples
========

!!! tip
IDEs are really useful when interacting with mockery objects. All mockery objects embed the [`github.com/stretchr/testify/mock.Mock`](https://pkg.go.dev/github.com/stretchr/testify/mock#Mock) object so you have access to both methods provided by mockery, and from testify itself. IDE auto-completion will show you all methods available for your use.

### Simple case

Given this interface:

```go title="string.go"
package example_project

//go:generate mockery --name Stringer
type Stringer interface {
String() string
}
```

Run: `go generate` (using the recommended config) and the the file `mock_Stringer_test.go` will be generated. You can now use this mock to create assertions and expectations.
Create a mock for this interface by specifying it in your config. We can then create a test using this new mock object:

```go title="string_test.go"
package example_project
Expand All @@ -36,10 +38,32 @@ func TestString(t *testing.T) {
}
```

Note that in combination with using the mock's constructor and the `.EXPECT()` directives, your test will automatically fail if the expected call is not made.
Note that in combination with using the mock's constructor and the [`.EXPECT()`](features.md#expecter-structs) directives, your test will automatically fail if the expected call is not made.

??? tip "Alternate way of specifying expectations"

You can also use the `github.com/stretchr/testify/mock.Mock` object directly (instead of using the `.EXPECT()` methods, which provide type-safe-ish assertions).

```go title="string_test.go"
func TestString(t *testing.T) {
mockStringer := NewMockStringer(t)
mockStringer.On("String").Return("mockery")
assert.Equal(t, "mockery", Foo(mockStringer))
}
```

We recommend always interacting with the assertions through `.EXPECT()` as mockery auto-generates methods that call out to `Mock.On()` themselves, providing you with some amount of compile-time safety. Consider if all your expectations for `String()` use the `Mock.On()` methods, and you decide to add an argument to `String()` to become `String(foo string)`. Now, your existing tests will only fail when you run them. If you had used `.EXPECT()` and regenerated your mocks after changing the function signature, your IDE, and the go compiler itself, would both tell you immediately that your expectations don't match the function signature.

```
foobar
```


### Function type case

!!! bug
Generating mocks for function types is likely not functioning in the `packages` config semantics. You'll likely need to revert to the legacy semantics as shown below.

Given this is in `send.go`

```go
Expand Down
103 changes: 1 addition & 102 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,7 @@ func (_m *Handler) HandleMessage(m pubsub.Message) error {

`packages` configuration
------------------------
:octicons-tag-24: v2.21.0 · :material-test-tube: Beta Feature

!!! warning
This feature is considered beta. The feature set has been solidified, but we are asking users to beta-test for any bugs. Use at your own risk. This warning will be updated as this feature matures.
:octicons-tag-24: v2.21.0

!!! info
See the [Migration Docs](migrating_to_packages.md) on how to migrate to this new feature.
Expand Down Expand Up @@ -146,104 +143,6 @@ packages:
Templated variables are only available when using the `packages` config feature.

Included with this feature is the ability to use templated strings for various configuration options. This is useful to define where your mocks are placed and how to name them. You can view the template variables available in the [Configuration](configuration.md#template-variables) section of the docs.

### Layouts

Using different configuration parameters, we can deploy our mocks on-disk in various ways. These are some common layouts:

!!! info "layouts"

=== "defaults"

```yaml
filename: "mock_{{.InterfaceName}}.go"
dir: "mocks/{{.PackagePath}}"
mockname: "Mock{{.InterfaceName}}"
outpkg: "{{.PackageName}}"
```

If these variables aren't specified, the above values will be applied to the config options. This strategy places your mocks into a separate `mocks/` directory.

**Interface Description**

| name | value |
|------|-------|
| `InterfaceName` | `MyDatabase` |
| `PackagePath` | `github.com/user/project/pkgName` |
| `PackageName` | `pkgName` |

**Output**

The mock will be generated at:

```
mocks/github.com/user/project/pkgName/mock_MyDatabase.go
```

The mock file will look like:

```go
package pkgName
import mock "github.com/stretchr/testify/mock"
type MockMyDatabase struct {
mock.Mock
}
```
=== "adjacent to interface"

!!! warning

Mockery does not protect against modifying original source code. Do not generate mocks using this config with uncommitted code changes.


```yaml
filename: "mock_{{.InterfaceName}}.go"
dir: "{{.InterfaceDir}}"
mockname: "Mock{{.InterfaceName}}"
outpkg: "{{.PackageName}}"
inpackage: True
```

Instead of the mocks being generated in a different folder, you may elect to generate the mocks alongside the original interface in your package. This may be the way most people define their configs, as it removes circular import issues that can happen with the default config.

For example, the mock might be generated along side the original source file like this:

```
./path/to/pkg/db.go
./path/to/pkg/mock_MyDatabase.go
```

**Interface Description**

| name | value |
|------|-------|
| `InterfaceName` | `MyDatabase` |
| `PackagePath` | `github.com/user/project/path/to/pkg`
| `PackagePathRelative` | `path/to/pkg` |
| `PackageName` | `pkgName` |
| `SourceFile` | `./path/to/pkg/db.go` |

**Output**

Mock file will be generated at:

```
./path/to/pkg/mock_MyDatabase.go
```

The mock file will look like:

```go
package pkgName
import mock "github.com/stretchr/testify/mock"
type MockMyDatabase struct {
mock.Mock
}
```

### Recursive package discovery

Expand Down
59 changes: 21 additions & 38 deletions docs/running.md
Original file line number Diff line number Diff line change
@@ -1,47 +1,30 @@
Running
========

Using `go generate` <small>recommended</small>
--------------------

`go generate` is often preferred as it give you more targeted generation of specific interfaces. Use `generate` as a directive above the interface you want to generate a mock for.

``` golang
package example_project

//go:generate mockery --name Root
type Root interface {
Foobar(s string) error
}
```

Then simply:

``` bash
$ go generate
09 Feb 23 22:55 CST INF Starting mockery dry-run=false version=v2.18.0
09 Feb 23 22:55 CST INF Using config: /Users/landonclipp/git/LandonTClipp/mockery/.mockery.yaml dry-run=false version=v2.18.0
09 Feb 23 22:55 CST INF Walking dry-run=false version=v2.18.0
09 Feb 23 22:55 CST INF Generating mock dry-run=false interface=Root qualified-name=github.com/vektra/mockery/v2/pkg/fixtures/example_project version=v2.18.0
If your `.mockery.yaml` file has been populated with the packages and interfaces you want mocked, mockery can be run with no arguments. Take for example how the mockery project itself is configured:

```yaml
quiet: False
keeptree: True
disable-version-string: True
with-expecter: True
mockname: "{{.InterfaceName}}"
filename: "{{.MockName}}.go"
outpkg: mocks
packages:
github.com/vektra/mockery/v2/pkg:
interfaces:
TypesPackage:
# Lots more config...
```

For all interfaces in project
------------------------------

If you provide `all: True`, you can generate mocks for the entire project. This is not recommended for larger projects as it can take a large amount of time parsing packages to generate mocks that you might never use.
From anywhere within your repo, you can simply call `mockery` once and it will find your config either by respecting the `#!yaml config` path you gave it, or by searching upwards from the current working directory.

```bash
$ mockery
09 Feb 23 22:47 CST INF Starting mockery dry-run=false version=v2.18.0
09 Feb 23 22:47 CST INF Using config: /Users/landonclipp/git/LandonTClipp/mockery/.mockery.yaml dry-run=false version=v2.18.0
09 Feb 23 22:47 CST INF Walking dry-run=false version=v2.18.0
09 Feb 23 22:47 CST INF Generating mock dry-run=false interface=A qualified-name=github.com/vektra/mockery/v2/pkg/fixtures version=v2.18.0
mockery
08 Jul 23 01:40 EDT INF Starting mockery dry-run=false version=v2.31.0
08 Jul 23 01:40 EDT INF Using config: /Users/landonclipp/git/LandonTClipp/mockery/.mockery.yaml dry-run=false version=v2.31.0
```

!!! note

Note that in some cases, using `//go:generate` may turn out to be slower than running for entire packages. `go:generate` calls mockery once for each `generate` directive, which means that mockery may need to parse the package multiple times, which is wasteful. Good judgement is recommended when determining the best option for your own project.

!!! note

For mockery to correctly generate mocks, the command has to be run on a module (i.e. your project has to have a go.mod file)
!!! question "Command line arguments"
It is valid to specify arguments from the command line. The configuration precedence is specified in the [Configuration](configuration.md#merging-precedence) docs.
2 changes: 1 addition & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ func (c *Config) subPackages(
if currentDepth == 0 && len(pkg.GoFiles) == 0 {
log.Error().
Err(ErrNoGoFilesFoundInRoot).
Str("documentation", "https://vektra.github.io/mockery/latest/notes/#error-no-go-files-found-in-root-search-path").
Str("documentation", logging.DocsURL("/notes/#error-no-go-files-found-in-root-search-path")).
Msg("package contains no go files")
return nil, ErrNoGoFilesFoundInRoot
}
Expand Down
19 changes: 19 additions & 0 deletions pkg/logging/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package logging

import (
"errors"
"fmt"
"os"
"runtime/debug"
"strings"
"time"

"github.com/rs/zerolog"
Expand Down Expand Up @@ -39,6 +41,23 @@ func GetSemverInfo() string {
return _defaultSemVer
}

func getMinorSemver(semver string) string {
split := strings.Split(semver, ".")
return strings.Join(split[0:2], ".")
}

// GetMinorSemver returns the semantic version up to and including the minor version.
func GetMinorSemver() string {
return getMinorSemver(GetSemverInfo())
}

func DocsURL(relativePath string) string {
if string(relativePath[0]) != "/" {
relativePath = "/" + relativePath
}
return fmt.Sprintf("https://vektra.github.io/mockery/%s%s", GetMinorSemver(), relativePath)
}

type timeHook struct{}

func (t timeHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
Expand Down
62 changes: 62 additions & 0 deletions pkg/logging/logging_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package logging

import (
"testing"
)

func Test_getMinorSemver(t *testing.T) {
tests := []struct {
name string
arg string
want string
}{
{
name: "default semver",
arg: "v0.0.0-dev",
want: "v0.0",
},
{
name: "example semver",
arg: "v2.0.1",
want: "v2.0",
},
{
name: "example semver with alpha notation",
arg: "v3.0.0-alpha.0",
want: "v3.0",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getMinorSemver(tt.arg); got != tt.want {
t.Errorf("getMinorSemver() = %v, want %v", got, tt.want)
}
})
}
}

func TestDocsURL(t *testing.T) {
tests := []struct {
name string
arg string
want string
}{
{
name: "url with no leading slash",
arg: "features",
want: "https://vektra.github.io/mockery/v0.0/features",
},
{
name: "url with leading slash",
arg: "/features",
want: "https://vektra.github.io/mockery/v0.0/features",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := DocsURL(tt.arg); got != tt.want {
t.Errorf("DocsURL() = %v, want %v", got, tt.want)
}
})
}
}

0 comments on commit 7696d20

Please sign in to comment.