From 563f88662c0d1d42690b19c0605e39907dce799c Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 2 Nov 2024 17:29:39 +0100 Subject: [PATCH 1/3] Add heuristic func to set plugin workspace base for windows containers correctly --- docs/docs/20-usage/20-workflow-syntax.md | 3 ++- pipeline/frontend/yaml/compiler/convert.go | 31 ++++++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/docs/docs/20-usage/20-workflow-syntax.md b/docs/docs/20-usage/20-workflow-syntax.md index 729c02f750..b9ad7fa528 100644 --- a/docs/docs/20-usage/20-workflow-syntax.md +++ b/docs/docs/20-usage/20-workflow-syntax.md @@ -546,7 +546,8 @@ The workspace can be customized using the workspace block in the YAML file: ``` :::note -Plugins will always have the workspace base at `/woodpecker` +Plugins will always have the workspace base at `/woodpecker`. +If windows is detected as container host os, it's `c:\woodpecker`. ::: The base attribute defines a shared base volume available to all steps. This ensures your source code, dependencies and compiled binaries are persisted and shared between steps. diff --git a/pipeline/frontend/yaml/compiler/convert.go b/pipeline/frontend/yaml/compiler/convert.go index 792e35505f..cd646c224c 100644 --- a/pipeline/frontend/yaml/compiler/convert.go +++ b/pipeline/frontend/yaml/compiler/convert.go @@ -18,6 +18,7 @@ import ( "fmt" "maps" "path" + "regexp" "strconv" "strings" @@ -33,10 +34,28 @@ import ( const ( // The pluginWorkspaceBase should not be changed, only if you are sure what you do. pluginWorkspaceBase = "/woodpecker" + // The pluginWorkspaceBaseWindows is like pluginWorkspaceBase but used if we detect windows as container host target. + pluginWorkspaceBaseWindows = `c:\woodpecker` // DefaultWorkspaceBase is set if not altered by the user. DefaultWorkspaceBase = pluginWorkspaceBase ) +var workspaceHasWindowsPattern = regexp.MustCompile(`^[a-zA-Z]:\\`) + +func (c *Compiler) checkRunOnWindowsHeuristics() bool { + // if user customized the workspace witch indicates it targets windows + if workspaceHasWindowsPattern.MatchString(c.workspaceBase) { + return true + } + + // if the platform filter targets windows + if strings.HasPrefix(strings.ToLower(c.metadata.Sys.Platform), "windows") { + return true + } + + return false +} + func (c *Compiler) createProcess(container *yaml_types.Container, stepType backend_types.StepType) (*backend_types.Step, error) { var ( uuid = ulid.Make() @@ -51,7 +70,11 @@ func (c *Compiler) createProcess(container *yaml_types.Container, stepType backe workspaceBase := c.workspaceBase if container.IsPlugin() { // plugins have a predefined workspace base to not tamper with entrypoint executables - workspaceBase = pluginWorkspaceBase + if c.checkRunOnWindowsHeuristics() { + workspaceBase = pluginWorkspaceBaseWindows + } else { + workspaceBase = pluginWorkspaceBase + } } workspaceVolume := fmt.Sprintf("%s_default:%s", c.prefix, workspaceBase) @@ -205,7 +228,11 @@ func (c *Compiler) stepWorkingDir(container *yaml_types.Container) string { } base := c.workspaceBase if container.IsPlugin() { - base = pluginWorkspaceBase + if c.checkRunOnWindowsHeuristics() { + base = pluginWorkspaceBaseWindows + } else { + base = pluginWorkspaceBase + } } return path.Join(base, c.workspacePath, container.Directory) } From d438bfbc4e09609fb079f8b2df2e76939a52514b Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 2 Nov 2024 17:39:58 +0100 Subject: [PATCH 2/3] Update pipeline/frontend/yaml/compiler/convert.go --- pipeline/frontend/yaml/compiler/convert.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pipeline/frontend/yaml/compiler/convert.go b/pipeline/frontend/yaml/compiler/convert.go index cd646c224c..05e7f2d989 100644 --- a/pipeline/frontend/yaml/compiler/convert.go +++ b/pipeline/frontend/yaml/compiler/convert.go @@ -228,6 +228,7 @@ func (c *Compiler) stepWorkingDir(container *yaml_types.Container) string { } base := c.workspaceBase if container.IsPlugin() { + // plugins have a predefined workspace base to not tamper with entrypoint executables if c.checkRunOnWindowsHeuristics() { base = pluginWorkspaceBaseWindows } else { From 4c7c8b90948542608c69c4df5caed3825148c701 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 2 Nov 2024 18:37:23 +0100 Subject: [PATCH 3/3] cover by tests --- .../frontend/yaml/compiler/compiler_test.go | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/pipeline/frontend/yaml/compiler/compiler_test.go b/pipeline/frontend/yaml/compiler/compiler_test.go index dadbcd5dd0..875c4c8050 100644 --- a/pipeline/frontend/yaml/compiler/compiler_test.go +++ b/pipeline/frontend/yaml/compiler/compiler_test.go @@ -299,6 +299,51 @@ func TestCompilerCompile(t *testing.T) { backConf: nil, expectedErr: "step 'dummy' depends on unknown step 'not exist'", }, + { + name: "workflow that targets windows as container host", + fronConf: &yaml_types.Workflow{ + Steps: yaml_types.ContainerList{ContainerList: []*yaml_types.Container{{ + Name: "hello powershell", + Image: "mcr.microsoft.com/windows/servercore:ltsc2022", + Commands: []string{"powershell.exe /c 'echo hello'"}, + }}}, + Workspace: yaml_types.Workspace{ + Base: "c:\\tmp", + }, + }, + backConf: &backend_types.Config{ + Stages: []*backend_types.Stage{ + { + Steps: []*backend_types.Step{{ + Name: "clone", + Type: backend_types.StepTypeClone, + Image: constant.DefaultClonePlugin, + OnSuccess: true, + Failure: "fail", + Volumes: []string{"test_default:c:\\woodpecker"}, + WorkingDir: "c:\\woodpecker/src/github.com/octocat/hello-world", + WorkspaceBase: `c:\woodpecker`, + Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"clone"}}}, + ExtraHosts: []backend_types.HostAlias{}, + }}, + }, {Steps: []*backend_types.Step{{ + Name: "hello powershell", + Type: backend_types.StepTypeCommands, + Image: "mcr.microsoft.com/windows/servercore:ltsc2022", + Commands: []string{"powershell.exe /c 'echo hello'"}, + OnSuccess: true, + Failure: "fail", + Volumes: []string{"test_default:c:\\tmp"}, + WorkingDir: "c:\\tmp/src/github.com/octocat/hello-world", + WorkspaceBase: `c:\tmp`, + Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"hello powershell"}}}, + ExtraHosts: []backend_types.HostAlias{}, + }}}, + }, + Networks: defaultNetworks, + Volumes: defaultVolumes, + }, + }, } for _, test := range tests {