hashicorp/go-slug

The path separator in .terraformignore file is dependant on the host OS

Opened this issue · 0 comments

The path separator in .terraformignore file is dependant on the host OS. For example, while running on windows, the paths in .terraformignore need to be separated of the foo\bar syntax and won't work if they are in the foo/bar syntax.

For repos with both windows and linux based engineers, this is causing us to add both windows and linux patterns to the .terraformignore file which we'd like to avoid.

Below test case demonstrates the issue. Also note that the terraformignore_test.go that comes in this repo fails when run on windows.

I'd be surprised if this is the intended behavior. One would expect the patterns to be always linux based (forward slash) irrespective of the runtime OS. But, removing support for baskslash patterns at this point would be a breaking change.

I'm happy to attempt a PR for a fix if I can get an agreement.

package slug

import (
        "log"
        "os"
        "path/filepath"
        "runtime"
        "testing"
)

func parseIgnoreFileContents(contents string) ([]rule, string) {
        tmpdir, _ := os.MkdirTemp("", "terraformignore")
        _ = os.WriteFile(filepath.Join(tmpdir, ".terraformignore"), []byte(contents), 0744)
        return parseIgnoreFile(tmpdir), tmpdir
}


// passes on windows
func TestTerraformIgnore_PathSeperator_Windows_WinPatterns(t *testing.T) {
        if runtime.GOOS != "windows" {
           t.SkipNow()
        }

        p, tmpdir := parseIgnoreFileContents(`foo\bar\**`)
        defer func() { _ = os.RemoveAll(tmpdir) }()

        assertMatch("foo\\bar\\test1", p)
        assertMatch("foo\\bar\\test1\\test2", p)
        assertNotMatch("xxx", p)
}

// fails on windows
func TestTerraformIgnore_PathSeperator_Windows_LinuxPatterns(t *testing.T) {
        if runtime.GOOS != "windows" {
           t.SkipNow()
        }

        p, tmpdir := parseIgnoreFileContents(`foo/bar/**`)
        defer func() { _ = os.RemoveAll(tmpdir) }()

        assertMatch("foo\\bar\\test1", p)
        assertMatch("foo\\bar\\test1\\test2", p)
        assertNotMatch("xxx", p)
}

// passes on linux
func TestTerraformIgnore_PathSeperator_Linux_LinuxPatterns(t *testing.T) {
        if runtime.GOOS == "windows" {
           t.SkipNow()
        }

        p, tmpdir := parseIgnoreFileContents(`foo/bar/**`)
        defer func() { _ = os.RemoveAll(tmpdir) }()

        assertMatch("foo/bar/test1", p)
        assertMatch("foo/bar/test1/test2", p)
        assertNotMatch("xxx", p)
}

// fails on linux
func TestTerraformIgnore_PathSeperator_Linux_WinPatterns(t *testing.T) {
        if runtime.GOOS == "windows" {
           t.SkipNow()
        }

        p, tmpdir := parseIgnoreFileContents(`foo\\bar\\**`)
        defer func() { _ = os.RemoveAll(tmpdir) }()

        assertMatch("foo/bar/test1", p)
        assertMatch("foo/bar/test1/test2", p)
        assertNotMatch("xxx", p)
}


func assertMatch(path string, rules []rule) {
        if !matchIgnoreRule(path, rules) {
                log.Fatalf("%s failed", path)
        }
}

func assertNotMatch(path string, rules []rule) {
        if matchIgnoreRule(path, rules) {
                log.Fatalf("%s failed", path)
        }
}