Skip to content

Commit

Permalink
Fix workingdirinit step for Windows tasks
Browse files Browse the repository at this point in the history
This change fixes an issue where Windows tasks would fail with an
error:
Failed to mkdir "\\ko-app\\workingdirinit": mkdir \ko-app\workingdirinit:
The system cannot find the path specified.
The workingdirinit step now correctly parses os.Args and appends 'C:'
on Windows if the path is absolute. Unit tests for Windows and Linux
have also been added.
  • Loading branch information
aiden-deloryn authored and tekton-robot committed Jun 28, 2023
1 parent 21828f3 commit 6ca7f3b
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 3 deletions.
27 changes: 24 additions & 3 deletions cmd/workingdirinit/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,37 @@ import (
"log"
"os"
"path/filepath"
"runtime"
"strings"
)

func main() {
for _, d := range os.Args {
p := filepath.Clean(d)
if !filepath.IsAbs(p) || strings.HasPrefix(p, "/workspace/") {
for i, d := range os.Args {
// os.Args[0] is the path to this executable, so we should skip it
if i == 0 {
continue
}

ws := cleanPath("/workspace/")
p := cleanPath(d)

if !filepath.IsAbs(p) || strings.HasPrefix(p, ws+string(filepath.Separator)) {
if err := os.MkdirAll(p, 0755); err != nil {
log.Fatalf("Failed to mkdir %q: %v", p, err)
}
}
}
}

func cleanPath(path string) string {
p := filepath.Clean(path)

if runtime.GOOS == "windows" {
// Append 'C:' if the path is absolute (i.e. it begins with a single '\')
if strings.HasPrefix(p, "\\") && !strings.HasPrefix(p, "\\\\") {
p = "C:" + p
}
}

return p
}
73 changes: 73 additions & 0 deletions cmd/workingdirinit/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//go:build linux
// +build linux

/*
Copyright 2023 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main

import (
"testing"

"github.com/google/go-cmp/cmp"
)

type testCase struct {
value string
expected string
}

var testCases []testCase = []testCase{
{
// Test trailing path separator
value: "/workspace/",
expected: "/workspace",
},
{
// Test workspace subdirectory
value: "/workspace/foobar",
expected: "/workspace/foobar",
},
{
// Test double path separator
value: "/foo//bar",
expected: "/foo/bar",
},
{
// Test relative path with './' prefix
value: "./foo/bar",
expected: "foo/bar",
},
{
// Test relative path with no prefix
value: "foo/bar",
expected: "foo/bar",
},
{
// Test empty string
value: "",
expected: ".",
},
}

func TestCleanPath(t *testing.T) {
for _, tc := range testCases {
diff := cmp.Diff(tc.expected, cleanPath(tc.value))

if diff != "" {
t.Errorf("diff(-want, +got): %s", diff)
}
}
}
83 changes: 83 additions & 0 deletions cmd/workingdirinit/main_windows_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//go:build windows
// +build windows

/*
Copyright 2023 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main

import (
"testing"

"github.com/google/go-cmp/cmp"
)

type testCase struct {
value string
expected string
}

var testCases []testCase = []testCase{
{
// Test trailing path separator
value: `/workspace/`,
expected: `C:\workspace`,
},
{
// Test workspace subdirectory
value: `/workspace/foobar`,
expected: `C:\workspace\foobar`,
},
{
// Test double path separator
value: `/foo//bar`,
expected: `C:\foo\bar`,
},
{
// Test relative path with './' prefix
value: `./foo/bar`,
expected: `foo\bar`,
},
{
// Test relative path with no prefix
value: `foo/bar`,
expected: `foo\bar`,
},
{
// Test empty string
value: ``,
expected: `.`,
},
{
// Test UNC path
value: `\\foo\bar`,
expected: `\\foo\bar`,
},
{
// Test native Windows path format
value: `C:\workspace\foobar`,
expected: `C:\workspace\foobar`,
},
}

func TestCleanPath(t *testing.T) {
for _, tc := range testCases {
diff := cmp.Diff(tc.expected, cleanPath(tc.value))

if diff != "" {
t.Errorf("diff(-want, +got): %s", diff)
}
}
}

0 comments on commit 6ca7f3b

Please sign in to comment.