testcontainers / testcontainers-node

Testcontainers is a NodeJS library that supports tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.
https://testcontainers.com
MIT License
1.79k stars 171 forks source link

.dockerignore doesn't honor subdirectory exclusion patterns #775

Open JonJam opened 4 weeks ago

JonJam commented 4 weeks ago

Expected Behaviour When using a .dockerfile as follows:

*
!example2
!example4/nested
!example5/example5.txt
!index.js

The above directories and files should be included in the build context.

Actual Behaviour example4/nested directory and example5/example5.txt are missing

Steps to Reproduce Define this test in checkout of repo:

import path from "path";
import { GenericContainer } from "./generic-container";

describe("GenericContainer", () => {
  jest.setTimeout(180_000);

  const fixtures = path.resolve(__dirname, "..", "..", "fixtures", "docker"); 

  it("should honour .dockerignore file", async () => {
    // ARRANGE
    const context = path.resolve(fixtures, "docker-with-dockerignore");
    const container = await GenericContainer.fromDockerfile(context).build();
    const startedContainer = await container.withExposedPorts(8080).start();

    const { output } = await startedContainer.exec(["find"]);

    console.log(output)

    expect(output).toContain("example2.txt");
    expect(output).toContain("example4.txt");
    expect(output).toContain("example5.txt");
    expect(output).not.toContain("example6.txt");

    await startedContainer.stop();
  });
});

Update .dockerignore in testcontainers-node-main/packages/testcontainers/fixtures/docker/docker-with-dockerignore/.dockerignore with:

*
!example2
!example4/nested
!example5/example5.txt
!index.js

The test will fail with:

GenericContainer › should honour .dockerignore file

    expect(received).toContain(expected) // indexOf

    Expected substring: "example4.txt"
    Received string:    ".
    ./example2
    ./example2/example2.txt
    ./index.js
    ./Dockerfile
    "

      18 |
      19 |     expect(output).toContain("example2.txt");
    > 20 |     expect(output).toContain("example4.txt");
         |                    ^
      21 |     expect(output).toContain("example5.txt");
      22 |     expect(output).not.toContain("example6.txt");

Debug notes

It seems like tar.pack is the issue, as it doesn't go into subdirectories:

  testcontainers [DEBUG] jonjam: For path ".dockerignore" isIgnored: true +2ms
  testcontainers [DEBUG] jonjam: For path "example1.txt" isIgnored: true +0ms
  testcontainers [DEBUG] jonjam: For path "example2" isIgnored: false +0ms
  testcontainers [DEBUG] jonjam: For path "example3" isIgnored: true +0ms
  testcontainers [DEBUG] jonjam: For path "example4" isIgnored: true +0ms
  testcontainers [DEBUG] jonjam: For path "example5" isIgnored: true +0ms
  testcontainers [DEBUG] jonjam: For path "example6" isIgnored: true +0ms
  testcontainers [DEBUG] jonjam: For path "example7" isIgnored: true +1ms
  testcontainers [DEBUG] jonjam: For path "exist1.txt" isIgnored: true +0ms
  testcontainers [DEBUG] jonjam: For path "index.js" isIgnored: false +0ms
  testcontainers [DEBUG] jonjam: For path "example2/example2.txt" isIgnored: false +3ms
cristianrgreco commented 4 weeks ago

Thanks for raising a detailed issue @JonJam, I can also reproduce it.

Looks like the dockerignore function from @balena/dockerignore works correctly by adding the correct rule, but the callback from tar.pack does not give the full path (example7/nested/file.txt), only the enclosing dir (example7/nested) which does not result in a match.

JonJam commented 4 weeks ago

No problem @cristianrgreco.

Sorry I forgot to add a note that I confirmed @balena/dockerignore works as expected in a node playground :)