From 1bd9a59d778f6afd768a0d9fdacf6d6d24462e7e Mon Sep 17 00:00:00 2001 From: Jake Runzer Date: Wed, 5 Feb 2025 17:55:33 -0800 Subject: [PATCH 01/14] docker run tests --- examples/node-bun/index.ts | 2 +- examples/node-bun/test.json | 5 ++ examples/node-npm/test.json | 5 ++ integration_tests/run_test.go | 160 ++++++++++++++++++++++++++++++++++ mise.toml | 5 +- 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 examples/node-bun/test.json create mode 100644 examples/node-npm/test.json create mode 100644 integration_tests/run_test.go diff --git a/examples/node-bun/index.ts b/examples/node-bun/index.ts index 2a5e4b8..7282220 100644 --- a/examples/node-bun/index.ts +++ b/examples/node-bun/index.ts @@ -1 +1 @@ -console.log("Hello via Bun!"); +console.log("hello from Bun " + Bun.version); diff --git a/examples/node-bun/test.json b/examples/node-bun/test.json new file mode 100644 index 0000000..2dbbfa4 --- /dev/null +++ b/examples/node-bun/test.json @@ -0,0 +1,5 @@ +[ + { + "expectedOutput": "hello from Bun" + } +] diff --git a/examples/node-npm/test.json b/examples/node-npm/test.json new file mode 100644 index 0000000..f089f73 --- /dev/null +++ b/examples/node-npm/test.json @@ -0,0 +1,5 @@ +[ + { + "expectedOutput": "hello from Node v23.5.0" + } +] diff --git a/integration_tests/run_test.go b/integration_tests/run_test.go new file mode 100644 index 0000000..d95e7e4 --- /dev/null +++ b/integration_tests/run_test.go @@ -0,0 +1,160 @@ +package integration_tests + +import ( + "bufio" + "context" + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/google/uuid" + "github.com/railwayapp/railpack/buildkit" + "github.com/railwayapp/railpack/core" + "github.com/railwayapp/railpack/core/app" + "github.com/stretchr/testify/require" +) + +type TestCase struct { + ExpectedOutput string `json:"expectedOutput"` + Envs map[string]string `json:"envs"` +} + +func runContainerWithTimeout(t *testing.T, imageName, expectedOutput string) error { + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() + + cmd := exec.CommandContext(ctx, "docker", "run", "--rm", imageName) + stdout, err := cmd.StdoutPipe() + if err != nil { + return fmt.Errorf("failed to create stdout pipe: %v", err) + } + stderr, err := cmd.StderrPipe() + if err != nil { + return fmt.Errorf("failed to create stderr pipe: %v", err) + } + + if err := cmd.Start(); err != nil { + return fmt.Errorf("failed to start container: %v", err) + } + + var output, errOutput strings.Builder + done := make(chan error, 1) + go func() { + scanner := bufio.NewScanner(stdout) + for scanner.Scan() { + line := scanner.Text() + output.WriteString(line + "\n") + if strings.Contains(line, expectedOutput) { + _ = cmd.Process.Kill() + done <- nil + return + } + } + done <- fmt.Errorf("container output:\n%s\nErrors:\n%s", output.String(), errOutput.String()) + }() + + go func() { + scanner := bufio.NewScanner(stderr) + for scanner.Scan() { + errOutput.WriteString(scanner.Text() + "\n") + } + }() + + select { + case <-ctx.Done(): + return fmt.Errorf("container timed out after 2 minutes") + case err := <-done: + if err != nil { + require.Contains(t, output.String(), expectedOutput, "container output did not contain expected string") + } + return err + case err := <-cmdDoneChan(cmd): + if err != nil && !strings.Contains(err.Error(), "signal: killed") { + return fmt.Errorf("container failed: %v", err) + } + require.Contains(t, output.String(), expectedOutput, "container output did not contain expected string") + return nil + } +} + +func cmdDoneChan(cmd *exec.Cmd) chan error { + ch := make(chan error, 1) + go func() { ch <- cmd.Wait() }() + return ch +} + +func TestExamplesIntegration(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + + wd, err := os.Getwd() + require.NoError(t, err) + + examplesDir := filepath.Join(filepath.Dir(wd), "examples") + entries, err := os.ReadDir(examplesDir) + require.NoError(t, err) + + for _, entry := range entries { + entry := entry // capture for parallel execution + if !entry.IsDir() { + continue + } + + testConfigPath := filepath.Join(examplesDir, entry.Name(), "test.json") + if _, err := os.Stat(testConfigPath); os.IsNotExist(err) { + continue + } + + testConfigBytes, err := os.ReadFile(testConfigPath) + require.NoError(t, err) + + var testCases []TestCase + err = json.Unmarshal(testConfigBytes, &testCases) + require.NoError(t, err) + + for i, testCase := range testCases { + testCase := testCase // capture for parallel execution + i := i + + testName := fmt.Sprintf("%s/case-%d", entry.Name(), i) + t.Run(testName, func(t *testing.T) { + t.Parallel() + + examplePath := filepath.Join(examplesDir, entry.Name()) + userApp, err := app.NewApp(examplePath) + if err != nil { + t.Fatalf("failed to create app: %v", err) + } + + env := app.NewEnvironment(&testCase.Envs) + buildResult, err := core.GenerateBuildPlan(userApp, env, &core.GenerateBuildPlanOptions{}) + if err != nil { + t.Fatalf("failed to generate build plan: %v", err) + } + if buildResult == nil { + t.Fatal("build result is nil") + } + + imageName := fmt.Sprintf("railpack-test-%s-%s", + strings.ToLower(strings.ReplaceAll(testName, "/", "-")), + strings.ToLower(uuid.New().String())) + + if err := buildkit.BuildWithBuildkitClient(examplePath, buildResult.Plan, buildkit.BuildWithBuildkitClientOptions{ + ImageName: imageName, + }); err != nil { + t.Fatalf("failed to build image: %v", err) + } + + if err := runContainerWithTimeout(t, imageName, testCase.ExpectedOutput); err != nil { + t.Fatal(err) + } + }) + } + } +} diff --git a/mise.toml b/mise.toml index c0d7132..ff7bef8 100644 --- a/mise.toml +++ b/mise.toml @@ -5,7 +5,10 @@ run = "go build -o bin/cli cmd/cli/main.go" run = "rm -rf bin" [tasks.test] -run = "go test ./..." +run = "go test -short ./..." + +[tasks.test-integration] +run = "go test ./integration_tests" [tasks.test-update-snapshots] run = "UPDATE_SNAPS=true go test ./..." From 4ddc876bf92d46bbedb758a67e6d7037eafa6595 Mon Sep 17 00:00:00 2001 From: Jake Runzer Date: Wed, 5 Feb 2025 18:00:14 -0800 Subject: [PATCH 02/14] unit test in ci test --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 64588e8..837fa35 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,5 +31,5 @@ jobs: - name: Vet run: go vet ./... - - name: Test - run: go test ./... + - name: Test Unit + run: go test -short ./... From 501e3d257218690a6f4f4859908a451791bdb038 Mon Sep 17 00:00:00 2001 From: Jake Runzer Date: Thu, 6 Feb 2025 10:30:47 -0800 Subject: [PATCH 03/14] run tests github action --- .github/workflows/run_tests.yml | 49 +++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/workflows/run_tests.yml diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml new file mode 100644 index 0000000..33faa7d --- /dev/null +++ b/.github/workflows/run_tests.yml @@ -0,0 +1,49 @@ +name: Run Tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + find-examples: + runs-on: ubuntu-latest + outputs: + examples: ${{ steps.find-examples.outputs.examples }} + steps: + - uses: actions/checkout@v4 + + - name: Find examples with test.json + id: find-examples + run: | + examples=$(find examples -name "test.json" -exec dirname {} \; | jq -R -s -c 'split("\n")[:-1]') + echo "examples=$examples" >> "$GITHUB_OUTPUT" + + test: + needs: find-examples + runs-on: ubuntu-latest + strategy: + matrix: + example: ${{ fromJson(needs.find-examples.outputs.examples) }} + fail-fast: false + + steps: + - uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: "1.21" + + - name: Start BuildKit + run: | + docker run --rm --privileged -d --name buildkit moby/buildkit + echo "BUILDKIT_HOST=docker-container://buildkit" >> $GITHUB_ENV + + - name: Install dependencies + run: go mod download + + - name: Run test for ${{ matrix.example }} + run: | + go test -v ./integration_tests -run "TestExamplesIntegration/${{ matrix.example }}" -timeout 30m From 22e05a368dd5a463d25d35409b58ee7eb61f5310 Mon Sep 17 00:00:00 2001 From: Jake Runzer Date: Thu, 6 Feb 2025 10:43:24 -0800 Subject: [PATCH 04/14] fix test name --- .github/workflows/run_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 33faa7d..7a4f962 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -17,7 +17,7 @@ jobs: - name: Find examples with test.json id: find-examples run: | - examples=$(find examples -name "test.json" -exec dirname {} \; | jq -R -s -c 'split("\n")[:-1]') + examples=$(find examples -name "test.json" -exec dirname {} \; | xargs -n 1 basename | jq -R -s -c 'split("\n")[:-1]') echo "examples=$examples" >> "$GITHUB_OUTPUT" test: From 7baa79c9c4a61f2e001536e1a44f5a4ffcf19f07 Mon Sep 17 00:00:00 2001 From: Jake Runzer Date: Thu, 6 Feb 2025 10:48:01 -0800 Subject: [PATCH 05/14] use a buildkit cache --- .github/workflows/run_tests.yml | 37 ++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 7a4f962..e328d6a 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -32,13 +32,37 @@ jobs: - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: - go-version: "1.21" + go-version: "1.23.4" + cache: true + + # Set up BuildKit cache + - name: Set up BuildKit cache + uses: actions/cache@v4 + with: + path: /tmp/buildkit-cache + key: ${{ runner.os }}-buildkit-${{ matrix.example }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildkit-${{ matrix.example }}- + ${{ runner.os }}-buildkit- - name: Start BuildKit run: | - docker run --rm --privileged -d --name buildkit moby/buildkit + # Start BuildKit with cache configuration + docker run --rm --privileged -d \ + -v /tmp/buildkit-cache:/cache \ + --name buildkit \ + --env BUILDKIT_DEBUG=1 \ + moby/buildkit \ + --debug \ + --oci-worker-gc=false \ + --oci-worker-snapshotter=overlayfs \ + --root /cache/buildkit + + # Wait for BuildKit to be ready + sleep 5 + echo "BUILDKIT_HOST=docker-container://buildkit" >> $GITHUB_ENV - name: Install dependencies @@ -47,3 +71,10 @@ jobs: - name: Run test for ${{ matrix.example }} run: | go test -v ./integration_tests -run "TestExamplesIntegration/${{ matrix.example }}" -timeout 30m + + # Export BuildKit cache after tests + - name: Export BuildKit cache + if: always() + run: | + docker exec buildkit buildctl prune --keep-storage 5GB + docker stop buildkit From 145e6db6bfd002cc794890b33a3602f8a3ed7e10 Mon Sep 17 00:00:00 2001 From: Jake Runzer Date: Thu, 6 Feb 2025 10:50:38 -0800 Subject: [PATCH 06/14] set mise timeout --- core/mise/mise.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/mise/mise.go b/core/mise/mise.go index 2754d65..078249e 100644 --- a/core/mise/mise.go +++ b/core/mise/mise.go @@ -80,6 +80,7 @@ func (m *Mise) runCmd(args ...string) (string, error) { cmd.Env = append(cmd.Env, fmt.Sprintf("MISE_CACHE_DIR=%s", cacheDir), fmt.Sprintf("MISE_DATA_DIR=%s", dataDir), + "MISE_HTTP_TIMEOUT=120", fmt.Sprintf("PATH=%s", os.Getenv("PATH")), ) From ab97954d41d975a6843bb1fdaae326c2a7790fb6 Mon Sep 17 00:00:00 2001 From: Jake Runzer Date: Thu, 6 Feb 2025 11:00:54 -0800 Subject: [PATCH 07/14] update buildkit cache config --- .github/workflows/run_tests.yml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index e328d6a..d9f7bd3 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -49,16 +49,21 @@ jobs: - name: Start BuildKit run: | + # Create cache directories + mkdir -p /tmp/buildkit-cache/buildkit-state + mkdir -p /tmp/buildkit-cache/buildkit-cache + # Start BuildKit with cache configuration docker run --rm --privileged -d \ - -v /tmp/buildkit-cache:/cache \ + -v /tmp/buildkit-cache/buildkit-state:/var/lib/buildkit \ + -v /tmp/buildkit-cache/buildkit-cache:/var/cache/buildkit \ --name buildkit \ - --env BUILDKIT_DEBUG=1 \ moby/buildkit \ --debug \ - --oci-worker-gc=false \ --oci-worker-snapshotter=overlayfs \ - --root /cache/buildkit + --oci-worker-max-parallelism=4 \ + --oci-worker-gc=true \ + --oci-worker-gc-keepstorage=5120000000 # Wait for BuildKit to be ready sleep 5 @@ -72,9 +77,7 @@ jobs: run: | go test -v ./integration_tests -run "TestExamplesIntegration/${{ matrix.example }}" -timeout 30m - # Export BuildKit cache after tests - - name: Export BuildKit cache + # Cleanup BuildKit + - name: Stop BuildKit if: always() - run: | - docker exec buildkit buildctl prune --keep-storage 5GB - docker stop buildkit + run: docker stop buildkit From 5806b18f9dbcf9846cbc2c354f272da4a414cb0f Mon Sep 17 00:00:00 2001 From: Jake Runzer Date: Thu, 6 Feb 2025 11:13:01 -0800 Subject: [PATCH 08/14] use buildkit import/export gha cache --- .github/workflows/run_tests.yml | 42 +++++++++++---------------------- buildkit/build.go | 31 ++++++++++++++++++++++++ integration_tests/run_test.go | 8 ++++++- 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index d9f7bd3..d760de2 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -37,33 +37,16 @@ jobs: go-version: "1.23.4" cache: true - # Set up BuildKit cache - - name: Set up BuildKit cache - uses: actions/cache@v4 - with: - path: /tmp/buildkit-cache - key: ${{ runner.os }}-buildkit-${{ matrix.example }}-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildkit-${{ matrix.example }}- - ${{ runner.os }}-buildkit- + # Set up GitHub Actions runtime for BuildKit cache + - name: Set up BuildKit GHA cache + uses: crazy-max/ghaction-github-runtime@v3 - name: Start BuildKit run: | - # Create cache directories - mkdir -p /tmp/buildkit-cache/buildkit-state - mkdir -p /tmp/buildkit-cache/buildkit-cache - - # Start BuildKit with cache configuration docker run --rm --privileged -d \ - -v /tmp/buildkit-cache/buildkit-state:/var/lib/buildkit \ - -v /tmp/buildkit-cache/buildkit-cache:/var/cache/buildkit \ --name buildkit \ - moby/buildkit \ - --debug \ - --oci-worker-snapshotter=overlayfs \ - --oci-worker-max-parallelism=4 \ - --oci-worker-gc=true \ - --oci-worker-gc-keepstorage=5120000000 + -e BUILDKIT_DEBUG=1 \ + moby/buildkit:latest # Wait for BuildKit to be ready sleep 5 @@ -74,10 +57,13 @@ jobs: run: go mod download - name: Run test for ${{ matrix.example }} + env: + ACTIONS_CACHE_URL: ${{ env.ACTIONS_CACHE_URL }} + ACTIONS_RUNTIME_TOKEN: ${{ env.ACTIONS_RUNTIME_TOKEN }} run: | - go test -v ./integration_tests -run "TestExamplesIntegration/${{ matrix.example }}" -timeout 30m - - # Cleanup BuildKit - - name: Stop BuildKit - if: always() - run: docker stop buildkit + # Add cache import/export flags to the test command + go test -v ./integration_tests \ + -run "TestExamplesIntegration/${{ matrix.example }}" \ + -timeout 30m \ + -buildkit-cache-import=type=gha,scope=${{ matrix.example }} \ + -buildkit-cache-export=type=gha,mode=max,scope=${{ matrix.example }} diff --git a/buildkit/build.go b/buildkit/build.go index 757d0d0..3b7494c 100644 --- a/buildkit/build.go +++ b/buildkit/build.go @@ -31,6 +31,8 @@ type BuildWithBuildkitClientOptions struct { SecretsHash string Secrets map[string]string Platform BuildPlatform + ImportCache string + ExportCache string } func BuildWithBuildkitClient(appDir string, plan *plan.BuildPlan, opts BuildWithBuildkitClientOptions) error { @@ -176,6 +178,22 @@ func BuildWithBuildkitClient(appDir string, plan *plan.BuildPlan, opts BuildWith }, } + // Add cache import if specified + if opts.ImportCache != "" { + solveOpts.CacheImports = append(solveOpts.CacheImports, client.CacheOptionsEntry{ + Type: "gha", + Attrs: parseKeyValue(opts.ImportCache), + }) + } + + // Add cache export if specified + if opts.ExportCache != "" { + solveOpts.CacheExports = append(solveOpts.CacheExports, client.CacheOptionsEntry{ + Type: "gha", + Attrs: parseKeyValue(opts.ExportCache), + }) + } + // Save the resulting filesystem to a directory if opts.OutputDir != "" { err = os.MkdirAll(opts.OutputDir, 0755) @@ -237,3 +255,16 @@ func getImageName(appDir string) string { } return name } + +// Helper function to parse key=value strings into a map +func parseKeyValue(s string) map[string]string { + attrs := make(map[string]string) + parts := strings.Split(s, ",") + for _, part := range parts { + kv := strings.SplitN(part, "=", 2) + if len(kv) == 2 { + attrs[kv[0]] = kv[1] + } + } + return attrs +} diff --git a/integration_tests/run_test.go b/integration_tests/run_test.go index d95e7e4..c9cecb4 100644 --- a/integration_tests/run_test.go +++ b/integration_tests/run_test.go @@ -4,6 +4,7 @@ import ( "bufio" "context" "encoding/json" + "flag" "fmt" "os" "os/exec" @@ -19,6 +20,9 @@ import ( "github.com/stretchr/testify/require" ) +var buildkitCacheImport = flag.String("buildkit-cache-import", "", "BuildKit cache import configuration") +var buildkitCacheExport = flag.String("buildkit-cache-export", "", "BuildKit cache export configuration") + type TestCase struct { ExpectedOutput string `json:"expectedOutput"` Envs map[string]string `json:"envs"` @@ -146,7 +150,9 @@ func TestExamplesIntegration(t *testing.T) { strings.ToLower(uuid.New().String())) if err := buildkit.BuildWithBuildkitClient(examplePath, buildResult.Plan, buildkit.BuildWithBuildkitClientOptions{ - ImageName: imageName, + ImageName: imageName, + ImportCache: *buildkitCacheImport, + ExportCache: *buildkitCacheExport, }); err != nil { t.Fatalf("failed to build image: %v", err) } From 67283b5bd776e72ebd327d741dd008b8a28ca6a3 Mon Sep 17 00:00:00 2001 From: Jake Runzer Date: Thu, 6 Feb 2025 11:20:47 -0800 Subject: [PATCH 09/14] update cache url --- .github/workflows/run_tests.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index d760de2..7d5eb3d 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -46,6 +46,8 @@ jobs: docker run --rm --privileged -d \ --name buildkit \ -e BUILDKIT_DEBUG=1 \ + -e ACTIONS_CACHE_URL=${{ env.ACTIONS_CACHE_URL }} \ + -e ACTIONS_RUNTIME_TOKEN=${{ env.ACTIONS_RUNTIME_TOKEN }} \ moby/buildkit:latest # Wait for BuildKit to be ready @@ -57,9 +59,6 @@ jobs: run: go mod download - name: Run test for ${{ matrix.example }} - env: - ACTIONS_CACHE_URL: ${{ env.ACTIONS_CACHE_URL }} - ACTIONS_RUNTIME_TOKEN: ${{ env.ACTIONS_RUNTIME_TOKEN }} run: | # Add cache import/export flags to the test command go test -v ./integration_tests \ @@ -67,3 +66,7 @@ jobs: -timeout 30m \ -buildkit-cache-import=type=gha,scope=${{ matrix.example }} \ -buildkit-cache-export=type=gha,mode=max,scope=${{ matrix.example }} + + - name: Stop BuildKit + if: always() + run: docker stop buildkit From 5140d6ba52b444038df8b1ffe1afdff3fcad76d9 Mon Sep 17 00:00:00 2001 From: Jake Runzer Date: Thu, 6 Feb 2025 11:23:36 -0800 Subject: [PATCH 10/14] fix url --- .github/workflows/run_tests.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 7d5eb3d..a5f6425 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -46,8 +46,6 @@ jobs: docker run --rm --privileged -d \ --name buildkit \ -e BUILDKIT_DEBUG=1 \ - -e ACTIONS_CACHE_URL=${{ env.ACTIONS_CACHE_URL }} \ - -e ACTIONS_RUNTIME_TOKEN=${{ env.ACTIONS_RUNTIME_TOKEN }} \ moby/buildkit:latest # Wait for BuildKit to be ready @@ -64,8 +62,8 @@ jobs: go test -v ./integration_tests \ -run "TestExamplesIntegration/${{ matrix.example }}" \ -timeout 30m \ - -buildkit-cache-import=type=gha,scope=${{ matrix.example }} \ - -buildkit-cache-export=type=gha,mode=max,scope=${{ matrix.example }} + -buildkit-cache-import="type=gha,url=${{ env.ACTIONS_CACHE_URL }},token=${{ env.ACTIONS_RUNTIME_TOKEN }},scope=${{ matrix.example }}" \ + -buildkit-cache-export="type=gha,url=${{ env.ACTIONS_CACHE_URL }},token=${{ env.ACTIONS_RUNTIME_TOKEN }},mode=max,scope=${{ matrix.example }}" - name: Stop BuildKit if: always() From a56706125fd24afca3dc14d9d6994927635233ed Mon Sep 17 00:00:00 2001 From: Jake Runzer Date: Thu, 6 Feb 2025 11:26:34 -0800 Subject: [PATCH 11/14] fail test on purpose --- examples/node-npm/test.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/node-npm/test.json b/examples/node-npm/test.json index f089f73..36975ea 100644 --- a/examples/node-npm/test.json +++ b/examples/node-npm/test.json @@ -1,5 +1,5 @@ [ { - "expectedOutput": "hello from Node v23.5.0" + "expectedOutput": "hello from Node v24.5.0" } ] From 63b3098086dc3c11ccd08722bd47806e011651e7 Mon Sep 17 00:00:00 2001 From: Jake Runzer Date: Thu, 6 Feb 2025 11:28:40 -0800 Subject: [PATCH 12/14] fix tests again --- examples/node-npm/test.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/node-npm/test.json b/examples/node-npm/test.json index 36975ea..f089f73 100644 --- a/examples/node-npm/test.json +++ b/examples/node-npm/test.json @@ -1,5 +1,5 @@ [ { - "expectedOutput": "hello from Node v24.5.0" + "expectedOutput": "hello from Node v23.5.0" } ] From 3f3d581b8dd1ec5ae77d9604220531f813ff2b88 Mon Sep 17 00:00:00 2001 From: Jake Runzer Date: Thu, 6 Feb 2025 11:45:03 -0800 Subject: [PATCH 13/14] add more tests --- core/providers/php/php.go | 3 ++- examples/go-cmd-dirs/cmd/server/main.go | 5 +++++ examples/go-cmd-dirs/test.json | 5 +++++ examples/go-mod/test.json | 5 +++++ examples/php-laravel-inertia/test.json | 5 +++++ examples/php-vanilla/test.json | 5 +++++ examples/python-pip/test.json | 5 +++++ examples/python-uv/main.py | 2 ++ examples/python-uv/test.json | 5 +++++ integration_tests/run_test.go | 19 +++++++++++++++++-- 10 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 examples/go-cmd-dirs/test.json create mode 100644 examples/go-mod/test.json create mode 100644 examples/php-laravel-inertia/test.json create mode 100644 examples/php-vanilla/test.json create mode 100644 examples/python-pip/test.json create mode 100644 examples/python-uv/test.json diff --git a/core/providers/php/php.go b/core/providers/php/php.go index 976a58b..e6b9c28 100644 --- a/core/providers/php/php.go +++ b/core/providers/php/php.go @@ -53,7 +53,8 @@ func (p *PhpProvider) Plan(ctx *generate.GenerateContext) error { // Install node nodeProvider := node.NodeProvider{} - if packageJson, err := nodeProvider.GetPackageJson(ctx.App); err == nil && packageJson != nil { + isNode := ctx.App.HasMatch("package.json") + if packageJson, err := nodeProvider.GetPackageJson(ctx.App); isNode && err == nil && packageJson != nil { ctx.EnterSubContext("node") nodePackages, err := nodeProvider.Packages(ctx, packageJson) diff --git a/examples/go-cmd-dirs/cmd/server/main.go b/examples/go-cmd-dirs/cmd/server/main.go index c4c5db9..adce4ef 100644 --- a/examples/go-cmd-dirs/cmd/server/main.go +++ b/examples/go-cmd-dirs/cmd/server/main.go @@ -1,6 +1,8 @@ package main import ( + "fmt" + "github.com/gin-gonic/gin" ) @@ -13,5 +15,8 @@ func main() { "message": "Hello world!", }) }) + + fmt.Println("Hello from Go") + r.Run() } diff --git a/examples/go-cmd-dirs/test.json b/examples/go-cmd-dirs/test.json new file mode 100644 index 0000000..54d3d2d --- /dev/null +++ b/examples/go-cmd-dirs/test.json @@ -0,0 +1,5 @@ +[ + { + "expectedOutput": "Hello from Go" + } +] diff --git a/examples/go-mod/test.json b/examples/go-mod/test.json new file mode 100644 index 0000000..54d3d2d --- /dev/null +++ b/examples/go-mod/test.json @@ -0,0 +1,5 @@ +[ + { + "expectedOutput": "Hello from Go" + } +] diff --git a/examples/php-laravel-inertia/test.json b/examples/php-laravel-inertia/test.json new file mode 100644 index 0000000..55f580f --- /dev/null +++ b/examples/php-laravel-inertia/test.json @@ -0,0 +1,5 @@ +[ + { + "expectedOutput": "Starting Nginx" + } +] diff --git a/examples/php-vanilla/test.json b/examples/php-vanilla/test.json new file mode 100644 index 0000000..62e921f --- /dev/null +++ b/examples/php-vanilla/test.json @@ -0,0 +1,5 @@ +[ + { + "expectedOutput": "Starting Nginx" + } +] diff --git a/examples/python-pip/test.json b/examples/python-pip/test.json new file mode 100644 index 0000000..3e31e57 --- /dev/null +++ b/examples/python-pip/test.json @@ -0,0 +1,5 @@ +[ + { + "expectedOutput": "Hello from Python" + } +] diff --git a/examples/python-uv/main.py b/examples/python-uv/main.py index cfc5307..08b2431 100644 --- a/examples/python-uv/main.py +++ b/examples/python-uv/main.py @@ -8,3 +8,5 @@ def hello(): if __name__ == "__main__": app.run(host="0.0.0.0", port=3333) + +print("Hello from Python UV!") diff --git a/examples/python-uv/test.json b/examples/python-uv/test.json new file mode 100644 index 0000000..44faa40 --- /dev/null +++ b/examples/python-uv/test.json @@ -0,0 +1,5 @@ +[ + { + "expectedOutput": "Hello from Python UV!" + } +] diff --git a/integration_tests/run_test.go b/integration_tests/run_test.go index c9cecb4..e8603d2 100644 --- a/integration_tests/run_test.go +++ b/integration_tests/run_test.go @@ -46,6 +46,13 @@ func runContainerWithTimeout(t *testing.T, imageName, expectedOutput string) err return fmt.Errorf("failed to start container: %v", err) } + // Ensure cleanup on function exit + defer func() { + if cmd.Process != nil { + _ = cmd.Process.Kill() + } + }() + var output, errOutput strings.Builder done := make(chan error, 1) go func() { @@ -54,11 +61,14 @@ func runContainerWithTimeout(t *testing.T, imageName, expectedOutput string) err line := scanner.Text() output.WriteString(line + "\n") if strings.Contains(line, expectedOutput) { - _ = cmd.Process.Kill() done <- nil return } } + if err := scanner.Err(); err != nil { + done <- fmt.Errorf("error reading stdout: %v", err) + return + } done <- fmt.Errorf("container output:\n%s\nErrors:\n%s", output.String(), errOutput.String()) }() @@ -75,8 +85,13 @@ func runContainerWithTimeout(t *testing.T, imageName, expectedOutput string) err case err := <-done: if err != nil { require.Contains(t, output.String(), expectedOutput, "container output did not contain expected string") + return err + } + // If we found the expected output, kill the container and return success + if cmd.Process != nil { + _ = cmd.Process.Kill() } - return err + return nil case err := <-cmdDoneChan(cmd): if err != nil && !strings.Contains(err.Error(), "signal: killed") { return fmt.Errorf("container failed: %v", err) From c16ce3a025182598ac0e7e881894178f7cacb047 Mon Sep 17 00:00:00 2001 From: Jake Runzer Date: Thu, 6 Feb 2025 11:47:48 -0800 Subject: [PATCH 14/14] update snapshot tests --- core/__snapshots__/core_test.snap | 198 +----------------------------- 1 file changed, 6 insertions(+), 192 deletions(-) diff --git a/core/__snapshots__/core_test.snap b/core/__snapshots__/core_test.snap index ef5952c..d3c7bfa 100755 --- a/core/__snapshots__/core_test.snap +++ b/core/__snapshots__/core_test.snap @@ -2831,10 +2831,6 @@ "apt-lists": { "directory": "/var/lib/apt/lists", "type": "locked" - }, - "mise": { - "directory": "/mise/cache", - "type": "shared" } }, "start": { @@ -2866,98 +2862,6 @@ "name": "packages:apt:nginx", "useSecrets": false }, - { - "assets": { - "mise.toml": "[tools]\n [tools.node]\n version = \"23.7.0\"\n [tools.npm]\n version = \"11.1.0\"\n" - }, - "commands": [ - { - "name": "MISE_INSTALL_PATH", - "value": "/usr/local/bin/mise" - }, - { - "name": "MISE_DATA_DIR", - "value": "/mise" - }, - { - "name": "MISE_CONFIG_DIR", - "value": "/mise" - }, - { - "name": "MISE_CACHE_DIR", - "value": "/mise/cache" - }, - { - "path": "/mise/shims" - }, - { - "caches": [ - "apt", - "apt-lists" - ], - "cmd": "sh -c 'apt-get update \u0026\u0026 apt-get install -y ca-certificates curl git'", - "customName": "install apt packages: ca-certificates curl git" - }, - { - "caches": [ - "mise" - ], - "cmd": "sh -c 'curl -fsSL https://mise.run | sh'", - "customName": "install mise" - }, - { - "customName": "create mise config", - "name": "mise.toml", - "path": "/etc/mise/config.toml" - }, - { - "caches": [ - "mise" - ], - "cmd": "sh -c 'mise trust -a \u0026\u0026 mise install'", - "customName": "install mise packages: node, npm" - } - ], - "dependsOn": [ - "packages:image" - ], - "name": "packages:mise", - "outputs": [ - "/mise/shims", - "/mise/installs", - "/usr/local/bin/mise", - "/etc/mise/config.toml", - "/root/.local/state/mise" - ], - "useSecrets": false - }, - { - "commands": [ - { - "name": "CI", - "value": "true" - }, - { - "name": "NODE_ENV", - "value": "production" - }, - { - "name": "NPM_CONFIG_PRODUCTION", - "value": "false" - }, - { - "name": "YARN_PRODUCTION", - "value": "false" - }, - { - "path": "/app/node_modules/.bin" - } - ], - "dependsOn": [ - "packages:mise" - ], - "name": "setup:node" - }, { "assets": { "nginx.conf": "worker_processes 5;\ndaemon off;\n\nworker_rlimit_nofile 8192;\n\nevents {\n worker_connections 4096;\n}\n\nhttp {\n include /etc/nginx/mime.types;\n index index.html index.htm index.php;\n\n default_type application/octet-stream;\n log_format main '$remote_addr - $remote_user [$time_local] $status '\n '\"$request\" $body_bytes_sent \"$http_referer\" '\n '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n\n access_log /dev/stdout;\n error_log /dev/stdout;\n sendfile on;\n tcp_nopush on;\n server_names_hash_bucket_size 128; # this seems to be required for some vhosts\n\n server {\n listen 0.0.0.0:80;\n listen [::]:80;\n\n server_name localhost;\n\n \n root /app;\n \n \n add_header X-Frame-Options \"SAMEORIGIN\";\n add_header X-Content-Type-Options \"nosniff\";\n \n index index.php;\n \n charset utf-8;\n \n \n \n \n \n location = /favicon.ico { access_log off; log_not_found off; }\n location = /robots.txt { access_log off; log_not_found off; }\n \n \n \n location ~ \\.php$ {\n fastcgi_pass 127.0.0.1:9000;\n fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;\n include /etc/nginx/fastcgi_params;\n include /etc/nginx/fastcgi.conf;\n }\n \n location ~ /\\.(?!well-known).* {\n deny all;\n }\n }\n}\n", @@ -2989,6 +2893,9 @@ "packages:apt:nginx" ], "name": "nginx:setup" + }, + { + "name": "packages:mise" } ] } @@ -3005,10 +2912,6 @@ "apt-lists": { "directory": "/var/lib/apt/lists", "type": "locked" - }, - "mise": { - "directory": "/mise/cache", - "type": "shared" } }, "start": { @@ -3060,98 +2963,6 @@ ], "name": "install" }, - { - "assets": { - "mise.toml": "[tools]\n [tools.node]\n version = \"23.7.0\"\n [tools.npm]\n version = \"11.1.0\"\n" - }, - "commands": [ - { - "name": "MISE_INSTALL_PATH", - "value": "/usr/local/bin/mise" - }, - { - "name": "MISE_DATA_DIR", - "value": "/mise" - }, - { - "name": "MISE_CONFIG_DIR", - "value": "/mise" - }, - { - "name": "MISE_CACHE_DIR", - "value": "/mise/cache" - }, - { - "path": "/mise/shims" - }, - { - "caches": [ - "apt", - "apt-lists" - ], - "cmd": "sh -c 'apt-get update \u0026\u0026 apt-get install -y ca-certificates curl git'", - "customName": "install apt packages: ca-certificates curl git" - }, - { - "caches": [ - "mise" - ], - "cmd": "sh -c 'curl -fsSL https://mise.run | sh'", - "customName": "install mise" - }, - { - "customName": "create mise config", - "name": "mise.toml", - "path": "/etc/mise/config.toml" - }, - { - "caches": [ - "mise" - ], - "cmd": "sh -c 'mise trust -a \u0026\u0026 mise install'", - "customName": "install mise packages: node, npm" - } - ], - "dependsOn": [ - "packages:image" - ], - "name": "packages:mise", - "outputs": [ - "/mise/shims", - "/mise/installs", - "/usr/local/bin/mise", - "/etc/mise/config.toml", - "/root/.local/state/mise" - ], - "useSecrets": false - }, - { - "commands": [ - { - "name": "CI", - "value": "true" - }, - { - "name": "NODE_ENV", - "value": "production" - }, - { - "name": "NPM_CONFIG_PRODUCTION", - "value": "false" - }, - { - "name": "YARN_PRODUCTION", - "value": "false" - }, - { - "path": "/app/node_modules/.bin" - } - ], - "dependsOn": [ - "packages:mise" - ], - "name": "setup:node" - }, { "assets": { "nginx.conf": "worker_processes 5;\ndaemon off;\n\nworker_rlimit_nofile 8192;\n\nevents {\n worker_connections 4096;\n}\n\nhttp {\n include /etc/nginx/mime.types;\n index index.html index.htm index.php;\n\n default_type application/octet-stream;\n log_format main '$remote_addr - $remote_user [$time_local] $status '\n '\"$request\" $body_bytes_sent \"$http_referer\" '\n '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n\n access_log /dev/stdout;\n error_log /dev/stdout;\n sendfile on;\n tcp_nopush on;\n server_names_hash_bucket_size 128; # this seems to be required for some vhosts\n\n server {\n listen 0.0.0.0:80;\n listen [::]:80;\n\n server_name localhost;\n\n \n root /app;\n \n \n add_header X-Frame-Options \"SAMEORIGIN\";\n add_header X-Content-Type-Options \"nosniff\";\n \n index index.php;\n \n charset utf-8;\n \n \n \n \n \n location = /favicon.ico { access_log off; log_not_found off; }\n location = /robots.txt { access_log off; log_not_found off; }\n \n \n \n location ~ \\.php$ {\n fastcgi_pass 127.0.0.1:9000;\n fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;\n include /etc/nginx/fastcgi_params;\n include /etc/nginx/fastcgi.conf;\n }\n \n location ~ /\\.(?!well-known).* {\n deny all;\n }\n }\n}\n", @@ -3183,6 +2994,9 @@ "packages:apt:nginx" ], "name": "nginx:setup" + }, + { + "name": "packages:mise" } ] }