Skip to content

chore!: extract image-related code to the top-level image package #2995

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

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

mdelapenya
Copy link
Member

  • chore: extract dockerignore to the image package
  • chore: extract image list to the image package
  • chore: extract save images to the image package
  • chore: extract image substitutors to the image package
  • chore: extract image build to the image package

What does this PR do?

This PR refactors the code to extract the docker image related code to a top-level package: image.

This package will be responsible of:

  • pulling images
  • saving images as tar files
  • parsing dockerignore files for image build
  • listing images
  • calculating image substitutors
  • building images

The related tests have been moved to the package, but there are "e2e" tests (they are actually using a ContainerRequest) that have been kept in the root package of the library.

Why is it important?

Separation of concerns, reducing the API surface in the root package.

@mdelapenya mdelapenya added chore Changes that do not impact the existing functionality breaking change Causing compatibility issues. labels Feb 24, 2025
@mdelapenya mdelapenya self-assigned this Feb 24, 2025
@mdelapenya mdelapenya requested a review from stevenh February 24, 2025 15:48
Copy link

netlify bot commented Feb 24, 2025

Deploy Preview for testcontainers-go ready!

Name Link
🔨 Latest commit afe5225
🔍 Latest deploy log https://app.netlify.com/sites/testcontainers-go/deploys/67bc94ef1ee2560008966eb3
😎 Deploy Preview https://deploy-preview-2995--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.

I like the idea of a smaller package with more focused responsibilities.

I've done a quick pass to capture some observations, however I wonder for if the current pattern of passing in a type which implements an interface hides the important elements making it harder to understand the logic and creating a hard dependency on external types such as types.ImageBuildOptions.

Thinking from first principles for a minute, would it be better if we made the image follow the our new best practices. For example have Build method take the required arguments + functional options for example:

func Build(ctx context.Context, context io.Reader, options ... Option) (string, error) {
...
}

That way we can avoid hard dependences for consumers on external types and provide a cleaner more maintainable package going forward, thoughts?

)

// Builder defines what is needed to build an image
type Builder interface {
Copy link
Contributor

Choose a reason for hiding this comment

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

question: does this need to be an interface or would a concrete type work better or simplify?

Also this doesn't seem to do a build, but more provide information to a builder, so is this the right name?

Comment on lines +23 to +26
GetContext() (io.Reader, error) // the path to the build context
GetDockerfile() string // the relative path to the Dockerfile, including the file itself
GetRepo() string // get repo label for image
GetTag() string // get tag label for image
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: make these more idiomatic, removing the Get prefixes.

@@ -0,0 +1,137 @@
package image
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: use a generated mock if we want to keep the interface.

fileLocation := filepath.Join(targetDir, ".dockerignore")
var excluded []string
exists := false
if f, openErr := os.Open(fileLocation); openErr == nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: return an error if its not fs.ErrExist

// List list images from the provider. If an image has multiple Tags, each tag is reported
// individually with the same ID and same labels
func List(ctx context.Context) ([]Info, error) {
images := []Info{}
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: use declared value instead

Suggested change
images := []Info{}
var images []Info

return fmt.Errorf("opening output file %w", err)
}
defer func() {
_ = outputFile.Close()
Copy link
Contributor

Choose a reason for hiding this comment

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

bug: you can loose data a not known it, name the return and assign on close.

Comment on lines +31 to +33
defer func() {
_ = imageReader.Close()
}()
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: no need for the wrap just call Close on a reader.

Suggested change
defer func() {
_ = imageReader.Close()
}()
defer imageReader.Close()

Comment on lines +36 to +37
_, err = outputFile.ReadFrom(imageReader)
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: fold for more idiomatic code

Suggested change
_, err = outputFile.ReadFrom(imageReader)
if err != nil {
if _, err = outputFile.ReadFrom(imageReader); err != nil {

@@ -0,0 +1,66 @@
package mock
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 just a move? Would a real mock be better?


// Build build an image from the given Builder, using the default docker client.
// It returns the first tag of the image.
func Build(ctx context.Context, img Builder) (string, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: having it be a Builder type and img name is confusing, lets get consistent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking change Causing compatibility issues. chore Changes that do not impact the existing functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants