railpack

Configure and troubleshoot Railpack builds, with emphasis on RAILPACK_* environment variables, railpack.json overlays, build-plan inspection, local CLI installation and usage, and local BuildKit containers. Use for Railpack provider configuration, custom install/build/start commands, Mise or Apt packages, build or runtime variables and secrets, generated-plan debugging, BUILDKIT_HOST errors, or running Railpack from a release or source checkout.

Install
npx skills add 'https://github.com/railwayapp/railpack/tree/main/.'
Incomplete bundle · no download
main · 21a254fScanned 2026-09-17

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗

core/plan/dockerignore_test.go

core/plan/dockerignore_test.goBrowse 1970 files
View on GitHub
← Back to SKILL.md
package plan import (	"os"	"path/filepath"	"slices"	"testing" 	"github.com/railwayapp/railpack/core/app"	"github.com/stretchr/testify/require") func TestCheckAndParseDockerignore(t *testing.T) {	t.Run("valid dockerignore file", func(t *testing.T) {		examplePath := filepath.Join("..", "..", "examples", "dockerignore")		testApp, err := app.NewApp(examplePath)		require.NoError(t, err) 		patterns, err := checkAndParseDockerignore(testApp) 		require.NoError(t, err)		require.NotNil(t, patterns)		require.Contains(t, patterns, "!negation_test/should_exist.txt")		require.Contains(t, patterns, "!negation_test/existing_folder") 		// Verify some expected patterns from examples/dockerignore/.dockerignore		// Note: patterns are parsed by the moby/patternmatcher library		expectedPatterns := []string{			".vscode",			".copier", // Leading slash is stripped			".env-specific",			".env*",			"__pycache__", // Trailing slash is stripped			"test",        // Leading slash is stripped			"tmp/*",       // Leading slash is stripped			"*.log",			"Justfile",			"TODO*",     // Leading slash is stripped			"README.md", // Leading slash is stripped			"docker-compose*.yml",		} 		for _, expected := range expectedPatterns {			require.Contains(t, patterns, expected, "Expected pattern %s not found in patterns", expected)		}	}) 	t.Run("inaccessible dockerignore", func(t *testing.T) {		// Create a temporary directory and file		tempDir, err := os.MkdirTemp("", "dockerignore-test")		require.NoError(t, err)		defer func() { _ = os.RemoveAll(tempDir) }() 		dockerignorePath := filepath.Join(tempDir, ".dockerignore")		err = os.WriteFile(dockerignorePath, []byte("*.log\nnode_modules\n"), 0644)		require.NoError(t, err) 		// Make the file unreadable (this simulates permission errors)		err = os.Chmod(dockerignorePath, 0000)		require.NoError(t, err)		defer func() { _ = os.Chmod(dockerignorePath, 0644) }() // Restore permissions for cleanup 		testApp, err := app.NewApp(tempDir)		require.NoError(t, err) 		// This should fail with a permission error		patterns, err := checkAndParseDockerignore(testApp)		require.Error(t, err)		require.Contains(t, err.Error(), "error reading .dockerignore")		require.Nil(t, patterns)	})} func TestDockerignoreExamples(t *testing.T) {	wd, err := os.Getwd()	require.NoError(t, err) 	examplesDir := filepath.Join(filepath.Dir(filepath.Dir(wd)), "examples")	entries, err := os.ReadDir(examplesDir)	require.NoError(t, err) 	expectedAsEmpty := []string{"mise-config"}	foundAsEmpty := []string{}	testedExamples := 0	for _, entry := range entries {		if !entry.IsDir() {			continue		} 		examplePath := filepath.Join(examplesDir, entry.Name())		dockerignorePath := filepath.Join(examplePath, ".dockerignore")		_, err := os.Stat(dockerignorePath)		if os.IsNotExist(err) {			continue		}		require.NoError(t, err) 		testedExamples++		t.Run(entry.Name(), func(t *testing.T) {			testApp, err := app.NewApp(examplePath)			require.NoError(t, err) 			ctx, err := NewDockerignoreContext(testApp)			require.NoError(t, err)			require.True(t, ctx.HasFile)			if slices.Contains(expectedAsEmpty, entry.Name()) {				foundAsEmpty = append(foundAsEmpty, entry.Name())				require.Empty(t, ctx.Excludes)				return			}			require.NotEmpty(t, ctx.Excludes)		})	} 	require.Positive(t, testedExamples, "expected at least one example with a .dockerignore")	require.ElementsMatch(t, expectedAsEmpty, foundAsEmpty)} func TestDockerignoreContext(t *testing.T) {	t.Run("new context", func(t *testing.T) {		tempDir, err := os.MkdirTemp("", "dockerignore-test")		require.NoError(t, err)		defer func() { _ = os.RemoveAll(tempDir) }() 		testApp, err := app.NewApp(tempDir)		require.NoError(t, err) 		ctx, err := NewDockerignoreContext(testApp)		require.NoError(t, err)		require.NotNil(t, ctx)		require.False(t, ctx.HasFile)		require.Nil(t, ctx.Excludes)	}) 	t.Run("context with dockerignore file", func(t *testing.T) {		examplePath := filepath.Join("..", "..", "examples", "dockerignore")		testApp, err := app.NewApp(examplePath)		require.NoError(t, err) 		ctx, err := NewDockerignoreContext(testApp)		require.NoError(t, err)		require.True(t, ctx.HasFile)		require.NotNil(t, ctx.Excludes)		require.Contains(t, ctx.Excludes, "!negation_test/should_exist.txt")		require.Contains(t, ctx.Excludes, "!negation_test/existing_folder")	}) 	t.Run("parse nonexistent file", func(t *testing.T) {		tempDir, err := os.MkdirTemp("", "dockerignore-test")		require.NoError(t, err)		defer func() { _ = os.RemoveAll(tempDir) }() 		testApp, err := app.NewApp(tempDir)		require.NoError(t, err) 		ctx, err := NewDockerignoreContext(testApp)		require.NoError(t, err)		require.False(t, ctx.HasFile)		require.Nil(t, ctx.Excludes)	}) 	t.Run("parse error handling", func(t *testing.T) {		// Create a temporary directory with an inaccessible .dockerignore		tempDir, err := os.MkdirTemp("", "dockerignore-test")		require.NoError(t, err)		defer func() { _ = os.RemoveAll(tempDir) }() 		dockerignorePath := filepath.Join(tempDir, ".dockerignore")		err = os.WriteFile(dockerignorePath, []byte("*.log\n"), 0644)		require.NoError(t, err) 		// Make the file unreadable		err = os.Chmod(dockerignorePath, 0000)		require.NoError(t, err)		defer func() { _ = os.Chmod(dockerignorePath, 0644) }() 		testApp, err := app.NewApp(tempDir)		require.NoError(t, err) 		ctx, err := NewDockerignoreContext(testApp)		require.Error(t, err)		require.Nil(t, ctx)	})} func TestDockerignoreDuplicatePatterns(t *testing.T) {	t.Run("duplicate patterns not removed from raw output", func(t *testing.T) {		tempDir, err := os.MkdirTemp("", "dockerignore-test")		require.NoError(t, err)		defer func() { _ = os.RemoveAll(tempDir) }() 		// Create test files		err = os.WriteFile(filepath.Join(tempDir, "keep.txt"), []byte("exists"), 0644)		require.NoError(t, err) 		// Create .dockerignore with duplicate patterns		dockerignoreContent := `*.log*.lognode_modules!keep.txt!keep.txt`		err = os.WriteFile(filepath.Join(tempDir, ".dockerignore"), []byte(dockerignoreContent), 0644)		require.NoError(t, err) 		testApp, err := app.NewApp(tempDir)		require.NoError(t, err) 		ctx, err := NewDockerignoreContext(testApp)		require.NoError(t, err) 		// Count occurrences of each pattern		logCount := 0		nodeModulesCount := 0		keepCount := 0		for _, pattern := range ctx.Excludes {			if pattern == "*.log" {				logCount++			}			if pattern == "node_modules" {				nodeModulesCount++			}			if pattern == "!keep.txt" {				keepCount++			}		} 		// Duplicates are preserved in raw output (will be handled downstream)		require.Equal(t, 2, logCount, "*.log pattern should appear twice")		require.Equal(t, 1, nodeModulesCount, "node_modules pattern should appear once")		require.Equal(t, 2, keepCount, "!keep.txt pattern should appear twice")	})} func TestCheckAndParseDockerignoreWithNegation(t *testing.T) {	t.Run("negated patterns preserved in output", func(t *testing.T) {		tempDir, err := os.MkdirTemp("", "dockerignore-test")		require.NoError(t, err)		defer func() { _ = os.RemoveAll(tempDir) }() 		// Create test files		err = os.MkdirAll(filepath.Join(tempDir, "negation_test", "existing_folder"), 0755)		require.NoError(t, err)		err = os.WriteFile(filepath.Join(tempDir, "negation_test", "should_exist.txt"), []byte("exists"), 0644)		require.NoError(t, err)		err = os.WriteFile(filepath.Join(tempDir, "negation_test", "existing_folder", "file.txt"), []byte("exists"), 0644)		require.NoError(t, err) 		// Create .dockerignore with mixed negation cases		dockerignoreContent := `negation_test/*!negation_test/should_exist.txt!negation_test/should_not_exist.txt!negation_test/folder_does_not_exist/!negation_test/existing_folder/`		err = os.WriteFile(filepath.Join(tempDir, ".dockerignore"), []byte(dockerignoreContent), 0644)		require.NoError(t, err) 		testApp, err := app.NewApp(tempDir)		require.NoError(t, err) 		patterns, err := checkAndParseDockerignore(testApp)		require.NoError(t, err) 		// All patterns (both exclude and negated) should be preserved		require.Contains(t, patterns, "negation_test/*")		require.Contains(t, patterns, "!negation_test/should_exist.txt")		require.Contains(t, patterns, "!negation_test/should_not_exist.txt")		require.Contains(t, patterns, "!negation_test/folder_does_not_exist")		require.Contains(t, patterns, "!negation_test/existing_folder")	})}