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

chore!: export DockerCompose type in compose package #2953

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

jasonyunicorn
Copy link
Contributor

@jasonyunicorn jasonyunicorn commented Jan 30, 2025

What does this PR do?

Exports the DockerCompose type in the compose packge.

BREAKING CHANGE: The DockerCompose interface was renamed to DockerComposer to prevent a
naming collision when exporting DockerCompose type.

Why is it important?

Returning an un-exported type from a constructor function limits the flexibility and usability of the returned instance. Callers can use the exported methods, but cannot declare variables of that type, pass instances to other functions, or embed them in structs without exposing the constructor itself.

Related issues

@jasonyunicorn jasonyunicorn requested a review from a team as a code owner January 30, 2025 18:03
Copy link

netlify bot commented Jan 30, 2025

Deploy Preview for testcontainers-go ready!

Name Link
🔨 Latest commit c55e0a1
🔍 Latest deploy log https://app.netlify.com/sites/testcontainers-go/deploys/67a19ce067b2c60008ef26c9
😎 Deploy Preview https://deploy-preview-2953--testcontainers-go.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link
Contributor

@stevenh stevenh left a comment

Choose a reason for hiding this comment

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

Could you clarify why this doesn't work already, as a quick test seems to indicate it does?

func TestHelloWorld(t *testing.T) {
	compose, err := compose.NewDockerCompose("test")
	require.NoError(t, err)
	err = compose.Down(context.Background())
	require.NoError(t, err)
}

@jasonyunicorn
Copy link
Contributor Author

@stevenh Yep, you are absolutely right! The type doesn't need to be exported for the methods which are exported to be accessible outside of the package.

@stevenh
Copy link
Contributor

stevenh commented Jan 30, 2025

@stevenh Yep, you are absolutely right! The type doesn't need to be exported for the methods which are exported to be accessible outside of the package.

So we can close this and the associated issue?

@xbc5
Copy link

xbc5 commented Jan 31, 2025

I think the documentation should clarify or emphasise the necessity to use the ComposeStack interface -- it isn't initially obvious that these are related.

@jasonyunicorn jasonyunicorn changed the title chore: expose DockerCompose type in the compose package chore: return ComposeStack interface in dockerCompose constructor functions Jan 31, 2025
@jasonyunicorn
Copy link
Contributor Author

I think the documentation should clarify or emphasise the necessity to use the ComposeStack interface -- it isn't initially obvious that these are related.

@xbc5 I agree, it's a bit confusing, but I believe the reason for the different interface name (ComposeStack) is because the previous interface (DockerComposer) is being deprecated. So, seems like there was a naming conflict.

Where would you like to see documentation updated?

@xbc5
Copy link

xbc5 commented Jan 31, 2025

I think the documentation should clarify or emphasise the necessity to use the ComposeStack interface -- it isn't initially obvious that these are related.

@xbc5 I agree, it's a bit confusing, but I believe the reason for the different interface name (ComposeStack) is because the previous interface (DockerComposer) is being deprecated. So, seems like there was a naming conflict.

Where would you like to see documentation updated?

Inline, on the NewDockerCompose factory; but if it returns the interface then it's not really necessary. It's not my place to say what this function should or should not return, but if it returns a struct, it should mention the interface.

Also, this is the first place I looked to get acquainted with the factory: so perhaps there too? Again, not necessary if it returns the interface.

Thanks for doing this.

@stevenh
Copy link
Contributor

stevenh commented Jan 31, 2025

Sorry I think you miss-understood my comment in the issue, I meant we should update the reason for the fix of exporting the returned type to detail that returning an unexported type restricts it's use, as it means it cannot be stored in a type or passed as a variable to a function, for example neither of the following are possible

type MyType struct {
   Stack *dockerCompose
}

func MyFunc(stack *dockerCompose) {
....
}

You should always return types and accept interfaces. For info on why see this.

@jasonyunicorn jasonyunicorn changed the title chore: return ComposeStack interface in dockerCompose constructor functions chore: export DockerCompose type in compose package Feb 1, 2025
@jasonyunicorn
Copy link
Contributor Author

@stevenh appreciate the review and sharing your wisdom! Great reference you linked there with returning types and accepting interfaces!

I went back to the original implementation, which exports the DockerCompose type in the constructor functions. Due to the naming conflict with the (deprecated) interface, that had to be renamed.

There was a cleanup helper method which used to accept a *dockerCompose, but now accepts a ComposeStack interface.

I don't suppose adding an interface implementation check (or interface compliance assertion) would be useful here to drive home the fact that the DockerCompose type implements the ComposeStack interface?

var _ ComposeStack = (*DockerCompose)(nil)

Copy link
Contributor

@stevenh stevenh left a comment

Choose a reason for hiding this comment

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

One clarifying question.

Due to the breaking change the PR title also needs a ! adding to it and "BREAKING CHANGE" to the description see conventional commits.

@@ -141,14 +141,15 @@ func TestDockerComposeAPIWithProfiles(t *testing.T) {

for name, test := range testcases {
t.Run(name, func(t *testing.T) {
var compose ComposeStack
Copy link
Contributor

Choose a reason for hiding this comment

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

question: is this and the change to cleanup needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, neither of those commits / changes are absolutely necessary, but I though it was a great place to practice the "accept interfaces" recommendation in the blog which you referenced.

I'm happy to remove / revert the changes / commits though.

In that case, we may want to consider adding the interface implementation check which I recommended. Otherwise, I could see future changes on the ComposeStack interface breaking the condition that DockerCompose satisfies said interface.

@jasonyunicorn jasonyunicorn changed the title chore: export DockerCompose type in compose package chore!: export DockerCompose type in compose package Feb 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Export dockerCompose type so consumers can store it in a variable and call Down
3 participants