Repository: crc-org/vfkit
Pull request #292: pkg/rest: refactor and simplify
Author: login: kolyshkin
Labels: name: lgtm
name: approved
name: ok-to-test
Created: 2025-03-31T18:35:09Z | Merged: 2025-04-15T14:55:58Z

This removes unused code from pkg/rest, and simplifies it.

Should not change functionality in any way.

Please see individual commits for details.

## Summary by Sourcery

Refactor and simplify the REST package by removing unused code and consolidating URI parsing logic

Enhancements:
- Simplified URI parsing logic by merging validation steps into the NewEndpoint function
- Removed case-insensitive scheme parsing and consolidated scheme conversion

Tests:
- Updated test cases to reflect new Endpoint creation and scheme parsing logic

Chores:
- Removed unused functions like validateRestfulURI and parseRestfulURI
- Removed unused import for cmdline package


Diff:
diff --git a/pkg/rest/rest.go b/pkg/rest/rest.go
index 172ae419..d9803e86 100644
--- a/pkg/rest/rest.go
+++ b/pkg/rest/rest.go
@@ -5,10 +5,8 @@ import (
 	"fmt"
 	"net/url"
 	"os"
-	"strings"
 	"syscall"
 
-	"github.com/crc-org/vfkit/pkg/cmdline"
 	"github.com/crc-org/vfkit/pkg/util"
 	"github.com/gin-gonic/gin"
 	"github.com/sirupsen/logrus"
@@ -146,24 +144,15 @@ func parseRestfulURI(inputURI string) (*url.URL, error) {
 	return restURI, err
 }
 
-// toRestScheme converts a string to a ServiceScheme
+// toRestScheme converts a string to a [ServiceScheme].
 func toRestScheme(s string) (ServiceScheme, error) {
-	switch strings.ToUpper(s) {
-	case "NONE":
+	switch s {
+	case "none":
 		return None, nil
-	case "UNIX":
+	case "unix":
 		return Unix, nil
-	case "TCP", "HTTP":
+	case "tcp", "http":
 		return TCP, nil
 	}
 	return None, fmt.Errorf("invalid scheme %s", s)
 }
-
-func validateRestfulURI(inputURI string) error {
-	if inputURI != cmdline.DefaultRestfulURI {
-		if _, err := parseRestfulURI(inputURI); err != nil {
-			return err
-		}
-	}
-	return nil
-}
diff --git a/pkg/rest/rest_test.go b/pkg/rest/rest_test.go
index 0228df29..fd6bffed 100644
--- a/pkg/rest/rest_test.go
+++ b/pkg/rest/rest_test.go
@@ -142,14 +142,6 @@ func TestToRestScheme(t *testing.T) {
 			want:    2,
 			wantErr: assert.Error,
 		},
-		{
-			name: "case doesnt matter",
-			args: args{
-				s: "UnIx",
-			},
-			want:    Unix,
-			wantErr: assert.NoError,
-		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -161,64 +153,3 @@ func TestToRestScheme(t *testing.T) {
 		})
 	}
 }
-
-func Test_validateRestfulURI(t *testing.T) {
-	type args struct {
-		inputURI string
-	}
-	tests := []struct {
-		name    string
-		args    args
-		wantErr bool
-	}{
-		{
-			name: "valid tcp",
-			args: args{
-				inputURI: "tcp://localhost:8080",
-			},
-			wantErr: false,
-		},
-		{
-			name: "invalid tcp - no host",
-			args: args{
-				inputURI: "tcp://",
-			},
-			wantErr: true,
-		},
-		{
-			name: "invalid scheme",
-			args: args{
-				inputURI: "http://localhost",
-			},
-			wantErr: true,
-		},
-		{
-			name: "valid uds",
-			args: args{
-				inputURI: "unix:///my/socket/goes/here/vfkit.sock",
-			},
-			wantErr: false,
-		},
-		{
-			name: "invalid uds - no path",
-			args: args{
-				inputURI: "unix://",
-			},
-			wantErr: true,
-		},
-		{
-			name: "none",
-			args: args{
-				inputURI: "none://",
-			},
-			wantErr: false,
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if err := validateRestfulURI(tt.args.inputURI); (err != nil) != tt.wantErr {
-				t.Errorf("validateRestfulURI() error = %v, wantErr %v", err, tt.wantErr)
-			}
-		})
-	}
-}


Reviews:
user: login: sourcery-ai[bot]
body: Hey @kolyshkin - I've reviewed your changes - here's some feedback:

**Overall Comments**:
- Consider adding comments to the `ServiceScheme` enum to explain what each value represents.
- The error messages in `NewEndpoint` could be improved to provide more context about the validation failure.

<details>
<summary>Here's what I looked at during the review</summary>

- 🟢 **General issues**: all looks good
- 🟢 **Security**: all looks good
- 🟢 **Testing**: all looks good
- 🟢 **Complexity**: all looks good
- 🟢 **Documentation**: all looks good
</details>

***

<details>
<summary>Sourcery is free for open source - if you like our reviews please consider sharing them ✨</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https://sourcery.ai)
- [Facebook](https://www.facebook.com/sharer/sharer.php?u=https://sourcery.ai)

</details>

<sub>
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
</sub>
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-31T18:36:54Z
user: login: gbraad
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-01T06:16:00Z
user: login: gbraad
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-01T06:17:30Z
user: login: kolyshkin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T06:33:45Z
user: login: kolyshkin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T06:38:02Z
user: login: gbraad
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-01T07:29:28Z
user: login: gbraad
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-01T07:32:38Z
user: login: gbraad
body: Haven't tested functionality, but looks cleaner.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-01T07:32:52Z
user: login: cfergeau
body: 3rd commit can be improved in my opinion, the first 2 look good to me.
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-09T09:23:08Z
user: login: kolyshkin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T16:42:43Z

Review comments:
diff_hunk: @@ -112,55 +132,15 @@ type VirtualMachineStateHandler interface {
 	SetVMState(c *gin.Context)
 }
 
-// parseRestfulURI validates the input URI and returns an URL object
-func parseRestfulURI(inputURI string) (*url.URL, error) {
-	restURI, err := url.ParseRequestURI(inputURI)
-	if err != nil {
-		return nil, err
-	}
-	scheme, err := toRestScheme(restURI.Scheme)
-	if err != nil {
-		return nil, err
-	}
-	if scheme == TCP && len(restURI.Host) < 1 {
-		return nil, errors.New("invalid TCP uri: missing host")
-	}
-	if scheme == TCP && len(restURI.Path) > 0 {
-		return nil, errors.New("invalid TCP uri: path is forbidden")
-	}
-	if scheme == TCP && restURI.Port() == "" {
-		return nil, errors.New("invalid TCP uri: missing port")
-	}
-	if scheme == Unix && len(restURI.Path) < 1 {
-		return nil, errors.New("invalid unix uri: missing path")
-	}
-	if scheme == Unix && len(restURI.Host) > 0 {
-		return nil, errors.New("invalid unix uri: host is forbidden")
-	}
-	if scheme == Unix && len(restURI.Path) > maxSocketPathLen() {
-		return nil, fmt.Errorf("invalid unix uri: socket path length exceeds macOS limits")
-	}
-	return restURI, err
-}
-
-// toRestScheme converts a string to a ServiceScheme
+// toRestScheme converts a string to a [ServiceScheme].
 func toRestScheme(s string) (ServiceScheme, error) {
-	switch strings.ToUpper(s) {
-	case "NONE":
+	switch s {
+	case "none":
 		return None, nil
-	case "UNIX":
+	case "unix":
path: pkg/rest/rest.go
user: login: gbraad
body: Can a `const` be used?
created_at: 2025-04-01T06:16:00Z
author_association: MEMBER
diff_hunk: @@ -112,55 +132,15 @@ type VirtualMachineStateHandler interface {
 	SetVMState(c *gin.Context)
 }
 
-// parseRestfulURI validates the input URI and returns an URL object
-func parseRestfulURI(inputURI string) (*url.URL, error) {
-	restURI, err := url.ParseRequestURI(inputURI)
-	if err != nil {
-		return nil, err
-	}
-	scheme, err := toRestScheme(restURI.Scheme)
-	if err != nil {
-		return nil, err
-	}
-	if scheme == TCP && len(restURI.Host) < 1 {
-		return nil, errors.New("invalid TCP uri: missing host")
-	}
-	if scheme == TCP && len(restURI.Path) > 0 {
-		return nil, errors.New("invalid TCP uri: path is forbidden")
-	}
-	if scheme == TCP && restURI.Port() == "" {
-		return nil, errors.New("invalid TCP uri: missing port")
-	}
-	if scheme == Unix && len(restURI.Path) < 1 {
-		return nil, errors.New("invalid unix uri: missing path")
-	}
-	if scheme == Unix && len(restURI.Host) > 0 {
-		return nil, errors.New("invalid unix uri: host is forbidden")
-	}
-	if scheme == Unix && len(restURI.Path) > maxSocketPathLen() {
-		return nil, fmt.Errorf("invalid unix uri: socket path length exceeds macOS limits")
-	}
-	return restURI, err
-}
-
-// toRestScheme converts a string to a ServiceScheme
+// toRestScheme converts a string to a [ServiceScheme].
 func toRestScheme(s string) (ServiceScheme, error) {
-	switch strings.ToUpper(s) {
path: pkg/rest/rest.go
user: login: gbraad
body: This is to ensure no mistakes are made when this is specified manually.
Either use `upper` or `lower`
created_at: 2025-04-01T06:17:30Z
author_association: MEMBER
diff_hunk: @@ -112,55 +132,15 @@ type VirtualMachineStateHandler interface {
 	SetVMState(c *gin.Context)
 }
 
-// parseRestfulURI validates the input URI and returns an URL object
-func parseRestfulURI(inputURI string) (*url.URL, error) {
-	restURI, err := url.ParseRequestURI(inputURI)
-	if err != nil {
-		return nil, err
-	}
-	scheme, err := toRestScheme(restURI.Scheme)
-	if err != nil {
-		return nil, err
-	}
-	if scheme == TCP && len(restURI.Host) < 1 {
-		return nil, errors.New("invalid TCP uri: missing host")
-	}
-	if scheme == TCP && len(restURI.Path) > 0 {
-		return nil, errors.New("invalid TCP uri: path is forbidden")
-	}
-	if scheme == TCP && restURI.Port() == "" {
-		return nil, errors.New("invalid TCP uri: missing port")
-	}
-	if scheme == Unix && len(restURI.Path) < 1 {
-		return nil, errors.New("invalid unix uri: missing path")
-	}
-	if scheme == Unix && len(restURI.Host) > 0 {
-		return nil, errors.New("invalid unix uri: host is forbidden")
-	}
-	if scheme == Unix && len(restURI.Path) > maxSocketPathLen() {
-		return nil, fmt.Errorf("invalid unix uri: socket path length exceeds macOS limits")
-	}
-	return restURI, err
-}
-
-// toRestScheme converts a string to a ServiceScheme
+// toRestScheme converts a string to a [ServiceScheme].
 func toRestScheme(s string) (ServiceScheme, error) {
-	switch strings.ToUpper(s) {
-	case "NONE":
+	switch s {
+	case "none":
 		return None, nil
-	case "UNIX":
+	case "unix":
path: pkg/rest/rest.go
user: login: kolyshkin
body: Do you mean, a const from the standard packages? I am not aware of any, please suggest.

Or do you mean to introduce and use own constant? If that's the case, I don't think it makes sense here.


created_at: 2025-04-01T06:33:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -112,55 +132,15 @@ type VirtualMachineStateHandler interface {
 	SetVMState(c *gin.Context)
 }
 
-// parseRestfulURI validates the input URI and returns an URL object
-func parseRestfulURI(inputURI string) (*url.URL, error) {
-	restURI, err := url.ParseRequestURI(inputURI)
-	if err != nil {
-		return nil, err
-	}
-	scheme, err := toRestScheme(restURI.Scheme)
-	if err != nil {
-		return nil, err
-	}
-	if scheme == TCP && len(restURI.Host) < 1 {
-		return nil, errors.New("invalid TCP uri: missing host")
-	}
-	if scheme == TCP && len(restURI.Path) > 0 {
-		return nil, errors.New("invalid TCP uri: path is forbidden")
-	}
-	if scheme == TCP && restURI.Port() == "" {
-		return nil, errors.New("invalid TCP uri: missing port")
-	}
-	if scheme == Unix && len(restURI.Path) < 1 {
-		return nil, errors.New("invalid unix uri: missing path")
-	}
-	if scheme == Unix && len(restURI.Host) > 0 {
-		return nil, errors.New("invalid unix uri: host is forbidden")
-	}
-	if scheme == Unix && len(restURI.Path) > maxSocketPathLen() {
-		return nil, fmt.Errorf("invalid unix uri: socket path length exceeds macOS limits")
-	}
-	return restURI, err
-}
-
-// toRestScheme converts a string to a ServiceScheme
+// toRestScheme converts a string to a [ServiceScheme].
 func toRestScheme(s string) (ServiceScheme, error) {
-	switch strings.ToUpper(s) {
path: pkg/rest/rest.go
user: login: kolyshkin
body: Can you point me out to a case in the code where it is specified manually?

From what I see, it is only used to parse a Scheme field from a structure obtained from url.ParseRequestURI, which ensures Scheme is lowercase, so we can expect the lowercased string here. This was noted in the commit message, too.
created_at: 2025-04-01T06:38:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -112,55 +132,15 @@ type VirtualMachineStateHandler interface {
 	SetVMState(c *gin.Context)
 }
 
-// parseRestfulURI validates the input URI and returns an URL object
-func parseRestfulURI(inputURI string) (*url.URL, error) {
-	restURI, err := url.ParseRequestURI(inputURI)
-	if err != nil {
-		return nil, err
-	}
-	scheme, err := toRestScheme(restURI.Scheme)
-	if err != nil {
-		return nil, err
-	}
-	if scheme == TCP && len(restURI.Host) < 1 {
-		return nil, errors.New("invalid TCP uri: missing host")
-	}
-	if scheme == TCP && len(restURI.Path) > 0 {
-		return nil, errors.New("invalid TCP uri: path is forbidden")
-	}
-	if scheme == TCP && restURI.Port() == "" {
-		return nil, errors.New("invalid TCP uri: missing port")
-	}
-	if scheme == Unix && len(restURI.Path) < 1 {
-		return nil, errors.New("invalid unix uri: missing path")
-	}
-	if scheme == Unix && len(restURI.Host) > 0 {
-		return nil, errors.New("invalid unix uri: host is forbidden")
-	}
-	if scheme == Unix && len(restURI.Path) > maxSocketPathLen() {
-		return nil, fmt.Errorf("invalid unix uri: socket path length exceeds macOS limits")
-	}
-	return restURI, err
-}
-
-// toRestScheme converts a string to a ServiceScheme
+// toRestScheme converts a string to a [ServiceScheme].
 func toRestScheme(s string) (ServiceScheme, error) {
-	switch strings.ToUpper(s) {
path: pkg/rest/rest.go
user: login: gbraad
body: I'll let @cfergeau decide as he maintains this codebase. 

I just notice that https://github.com/crc-org/vfkit/pull/292/files#diff-e8eb5f08837c85d4c2db17fa463051c4a787efb7cbc9883092f53b24a48514e1R32 uses the input that comes from the request parse; and it assumes the format to be returned always to be lower. Defensive programming is not wrong, as this is not code to be performant or such (and mistakes have been made before). Overall, this looks more maintainable.

created_at: 2025-04-01T07:29:28Z
author_association: MEMBER
diff_hunk: @@ -112,55 +132,15 @@ type VirtualMachineStateHandler interface {
 	SetVMState(c *gin.Context)
 }
 
-// parseRestfulURI validates the input URI and returns an URL object
-func parseRestfulURI(inputURI string) (*url.URL, error) {
-	restURI, err := url.ParseRequestURI(inputURI)
-	if err != nil {
-		return nil, err
-	}
-	scheme, err := toRestScheme(restURI.Scheme)
-	if err != nil {
-		return nil, err
-	}
-	if scheme == TCP && len(restURI.Host) < 1 {
-		return nil, errors.New("invalid TCP uri: missing host")
-	}
-	if scheme == TCP && len(restURI.Path) > 0 {
-		return nil, errors.New("invalid TCP uri: path is forbidden")
-	}
-	if scheme == TCP && restURI.Port() == "" {
-		return nil, errors.New("invalid TCP uri: missing port")
-	}
-	if scheme == Unix && len(restURI.Path) < 1 {
-		return nil, errors.New("invalid unix uri: missing path")
-	}
-	if scheme == Unix && len(restURI.Host) > 0 {
-		return nil, errors.New("invalid unix uri: host is forbidden")
-	}
-	if scheme == Unix && len(restURI.Path) > maxSocketPathLen() {
-		return nil, fmt.Errorf("invalid unix uri: socket path length exceeds macOS limits")
-	}
-	return restURI, err
-}
-
-// toRestScheme converts a string to a ServiceScheme
+// toRestScheme converts a string to a [ServiceScheme].
 func toRestScheme(s string) (ServiceScheme, error) {
-	switch strings.ToUpper(s) {
-	case "NONE":
+	switch s {
+	case "none":
 		return None, nil
-	case "UNIX":
+	case "unix":
path: pkg/rest/rest.go
user: login: gbraad
body: I thought they had... https://pkg.go.dev/net/url#pkg-constants "Section is emptry" :-/
created_at: 2025-04-01T07:32:38Z
author_association: MEMBER
diff_hunk: @@ -25,14 +25,36 @@ type Endpoint struct {
 }
 
 func NewEndpoint(input string) (*Endpoint, error) {
-	uri, err := parseRestfulURI(input)
+	uri, err := url.ParseRequestURI(input)
 	if err != nil {
 		return nil, err
 	}
 	scheme, err := toRestScheme(uri.Scheme)
 	if err != nil {
 		return nil, err
 	}
+	switch scheme {
+	case TCP:
+		if len(uri.Host) < 1 {
path: pkg/rest/rest.go
user: login: cfergeau
body: `toRestScheme` is only called once after this change, and it is mostly checking that the uri scheme is a valid one, and then in this `switch`/`case`, we do more validation on the URI.
I’d move `toRestScheme` and the validation code from `parseRestfulURI` to a single `validateURI(uri)` method which would do everything at once.
I prefer to have the validation code in a separate function to avoid cluttering `NewEndpoint`.
created_at: 2025-04-09T09:22:41Z
author_association: COLLABORATOR
diff_hunk: @@ -25,14 +25,36 @@ type Endpoint struct {
 }
 
 func NewEndpoint(input string) (*Endpoint, error) {
-	uri, err := parseRestfulURI(input)
+	uri, err := url.ParseRequestURI(input)
 	if err != nil {
 		return nil, err
 	}
 	scheme, err := toRestScheme(uri.Scheme)
 	if err != nil {
 		return nil, err
 	}
+	switch scheme {
+	case TCP:
+		if len(uri.Host) < 1 {
path: pkg/rest/rest.go
user: login: kolyshkin
body: I've removed the third commit.
created_at: 2025-04-09T16:42:43Z
author_association: CONTRIBUTOR

PR comments:
user: login: sourcery-ai[bot]
created_at: 2025-03-31T18:35:14Z
body: <!-- Generated by sourcery-ai[bot]: start review_guide -->

## Reviewer's Guide by Sourcery

Refactored the REST package by removing unused code, simplifying URI parsing, and updating tests to reflect these changes. The URI parsing and validation logic has been consolidated into the `NewEndpoint` function. Unnecessary functions and case-insensitive scheme parsing were removed.

#### Sequence diagram for Endpoint creation

```mermaid
sequenceDiagram
  participant Client
  participant NewEndpoint
  participant url.ParseRequestURI
  participant toRestScheme

  Client->>NewEndpoint: NewEndpoint(input)
  NewEndpoint->>url.ParseRequestURI: url.ParseRequestURI(input)
  url.ParseRequestURI-->>NewEndpoint: Returns URI
  NewEndpoint->>toRestScheme: toRestScheme(URI.Scheme)
  toRestScheme-->>NewEndpoint: Returns ServiceScheme
  NewEndpoint-->>Client: Returns Endpoint, error
```

#### Updated class diagram for Endpoint

```mermaid
classDiagram
  class Endpoint {
    Host: string
    Path: string
    Scheme: ServiceScheme
  }

  class ServiceScheme {
    None
    Unix
    TCP
  }

  Endpoint -- ServiceScheme : has a
```

### File-Level Changes

| Change | Details | Files |
| ------ | ------- | ----- |
| Consolidated URI parsing and validation logic into the `NewEndpoint` function. | <ul><li>Merged the URI parsing and validation steps into the `NewEndpoint` function.</li><li>Replaced direct `url.ParseRequestURI` calls with calls to `NewEndpoint`.</li></ul> | `pkg/rest/rest.go`<br/>`pkg/rest/rest_test.go` |
| Removed unused code and simplified scheme parsing. | <ul><li>Removed the `validateRestfulURI` and `parseRestfulURI` functions.</li><li>Removed case-insensitive scheme parsing in `toRestScheme`.</li><li>Removed unused import for `cmdline` package.</li></ul> | `pkg/rest/rest.go`<br/>`pkg/rest/rest_test.go` |
| Updated tests to reflect changes in `Endpoint` creation and scheme parsing. | <ul><li>Updated test cases to use `NewEndpoint` instead of `parseRestfulURI`.</li><li>Adjusted test assertions to match the new `Endpoint` struct and scheme parsing logic.</li></ul> | `pkg/rest/rest_test.go` |

---

<details>
<summary>Tips and commands</summary>

#### Interacting with Sourcery

- **Trigger a new review:** Comment `@sourcery-ai review` on the pull request.
- **Continue discussions:** Reply directly to Sourcery's review comments.
- **Generate a GitHub issue from a review comment:** Ask Sourcery to create an
  issue from a review comment by replying to it. You can also reply to a
  review comment with `@sourcery-ai issue` to create an issue from it.
- **Generate a pull request title:** Write `@sourcery-ai` anywhere in the pull
  request title to generate a title at any time. You can also comment
  `@sourcery-ai title` on the pull request to (re-)generate the title at any time.
- **Generate a pull request summary:** Write `@sourcery-ai summary` anywhere in
  the pull request body to generate a PR summary at any time exactly where you
  want it. You can also comment `@sourcery-ai summary` on the pull request to
  (re-)generate the summary at any time.
- **Generate reviewer's guide:** Comment `@sourcery-ai guide` on the pull
  request to (re-)generate the reviewer's guide at any time.
- **Resolve all Sourcery comments:** Comment `@sourcery-ai resolve` on the
  pull request to resolve all Sourcery comments. Useful if you've already
  addressed all the comments and don't want to see them anymore.
- **Dismiss all Sourcery reviews:** Comment `@sourcery-ai dismiss` on the pull
  request to dismiss all existing Sourcery reviews. Especially useful if you
  want to start fresh with a new review - don't forget to comment
  `@sourcery-ai review` to trigger a new review!
- **Generate a plan of action for an issue:** Comment `@sourcery-ai plan` on
  an issue to generate a plan of action for it.

#### Customizing Your Experience

Access your [dashboard](https://app.sourcery.ai) to:
- Enable or disable review features such as the Sourcery-generated pull request
  summary, the reviewer's guide, and others.
- Change the review language.
- Add, remove or edit custom review instructions.
- Adjust other review settings.

#### Getting Help

- [Contact our support team](mailto:support@sourcery.ai) for questions or feedback.
- Visit our [documentation](https://docs.sourcery.ai) for detailed guides and information.
- Keep in touch with the Sourcery team by following us on [X/Twitter](https://x.com/SourceryAI), [LinkedIn](https://www.linkedin.com/company/sourcery-ai/) or [GitHub](https://github.com/sourcery-ai).

</details>

<!-- Generated by sourcery-ai[bot]: end review_guide -->
author_association: NONE
user: login: openshift-ci[bot]
created_at: 2025-03-31T18:35:21Z
body: Hi @kolyshkin. Thanks for your PR.

I'm waiting for a [crc-org](https://github.com/orgs/crc-org/people) member to verify that this patch is reasonable to test. If it is, they should reply with `/ok-to-test` on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should [join the org](https://github.com/orgs/crc-org/people) to skip this step.

Once the patch is verified, the new status will be reflected by the `ok-to-test` label.

I understand the commands that are listed [here](https://go.k8s.io/bot-commands?repo=crc-org%2Fvfkit).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository.
</details>

author_association: NONE
user: login: kolyshkin
created_at: 2025-04-09T16:42:07Z
body: > 3rd commit can be improved in my opinion, the first 2 look good to me.

I have remove the third commit.
author_association: CONTRIBUTOR
user: login: cfergeau
created_at: 2025-04-10T10:46:46Z
body: > > 3rd commit can be improved in my opinion, the first 2 look good to me.
> 
> I have remove the third commit.

Are you planning to do some work on it? Or should we merge this as is?
author_association: COLLABORATOR
user: login: cfergeau
created_at: 2025-04-10T14:42:27Z
body: /ok-to-test

author_association: COLLABORATOR
user: login: cfergeau
created_at: 2025-04-15T14:46:02Z
body: /lgtm
author_association: COLLABORATOR
user: login: cfergeau
created_at: 2025-04-15T14:53:01Z
body: /approve
author_association: COLLABORATOR
user: login: openshift-ci[bot]
created_at: 2025-04-15T14:53:07Z
body: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/crc-org/vfkit/pull/292#issuecomment-2805740359" title="Approved">cfergeau</a>*, *<a href="https://github.com/crc-org/vfkit/pull/292#pullrequestreview-2731749245" title="Approved">gbraad</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=crc-org%2Fvfkit).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/crc-org/vfkit/blob/main/OWNERS)~~ [cfergeau]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
author_association: NONE