-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtask.go
143 lines (121 loc) · 3.73 KB
/
task.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package forge
import (
"context"
"fmt"
"path/filepath"
"regexp"
"github.com/frantjc/forge/azuredevops"
xos "github.com/frantjc/x/os"
)
type Task struct {
Task string
Inputs map[string]string
Execution string
}
func (o *Task) Run(ctx context.Context, containerRuntime ContainerRuntime, opts ...RunOpt) error {
opt := runOptsWithDefaults(opts...)
ref, err := azuredevops.Parse(o.Task)
if err != nil {
return err
}
task, err := azuredevops.GetReferenceTask(ref)
if err != nil {
return err
}
containerConfig, err := taskToContainerConfig(ref, task, o.Execution, o.Inputs, opt)
if err != nil {
return err
}
containerConfig.Mounts = overrideMounts(containerConfig.Mounts, opt.Mounts...)
image, err := pullImageForExecution(ctx, containerRuntime, o.Execution)
if err != nil {
return err
}
container, err := createSleepingContainer(ctx, containerRuntime, image, containerConfig, opt)
if err != nil {
return err
}
defer container.Stop(ctx) //nolint:errcheck
defer container.Remove(ctx) //nolint:errcheck
if exitCode, err := container.Exec(ctx, containerConfig, opt.Streams); err != nil {
return err
} else if exitCode > 0 {
return xos.NewExitCodeError(ErrContainerExitedWithNonzeroExitCode, exitCode)
}
return nil
}
func taskReferenceToDirectory(ref *azuredevops.TaskReference) (string, error) {
if ref.IsLocal() {
return filepath.Abs(ref.Path)
}
return "", fmt.Errorf("remote Azure DevOps tasks are not implemented")
}
func taskToContainerConfig(ref *azuredevops.TaskReference, task *azuredevops.Task, execution string, inputs map[string]string, opt *RunOpts) (*ContainerConfig, error) {
taskDir, err := taskReferenceToDirectory(ref)
if err != nil {
return nil, err
}
if task == nil {
return nil, fmt.Errorf("nil task")
}
var (
target string
workingDirectory string
env = make([]string, len(task.Inputs))
)
if task.Executions != nil {
switch execution {
case azuredevops.ExecutionNode:
target = task.Executions.Node.Target
workingDirectory = task.Executions.Node.WorkingDirectory
case azuredevops.ExecutionNode16:
target = task.Executions.Node16.Target
workingDirectory = task.Executions.Node16.WorkingDirectory
case azuredevops.ExecutionNode10:
target = task.Executions.Node10.Target
workingDirectory = task.Executions.Node10.WorkingDirectory
default:
return nil, fmt.Errorf("powershell task not supported")
}
} else {
return nil, fmt.Errorf("task has no executions")
}
if target == "" {
return nil, fmt.Errorf("exeuction has no target")
}
for i, input := range task.Inputs {
name := "INPUT_" + regexp.MustCompile("[ .]").ReplaceAllString(task.Name, "_")
if in, ok := inputs[input.Name]; ok {
env[i] = fmt.Sprintf("%s=%s", name, in)
} else if input.Required {
return nil, fmt.Errorf("required input %s not supplied: %s", input.Name, input.HelpMarkDown)
} else {
env[i] = fmt.Sprintf("%s=%s", name, input.DefaultValue)
}
}
return &ContainerConfig{
Entrypoint: []string{"node", filepath.Join(AzureDevOpsTaskWorkingDir(opt.WorkingDir), target)},
Mounts: []Mount{
{
Source: taskDir,
Destination: AzureDevOpsTaskWorkingDir(opt.WorkingDir),
},
},
Env: env,
WorkingDir: filepath.Join(AzureDevOpsTaskWorkingDir(opt.WorkingDir), workingDirectory),
}, nil
}
func pullImageForExecution(ctx context.Context, containerRuntime ContainerRuntime, execution string) (Image, error) {
ref := ""
switch execution {
case azuredevops.ExecutionNode:
ref = NodeImageReference
case azuredevops.ExecutionNode16:
ref = Node16ImageReference
case azuredevops.ExecutionNode10:
ref = Node10ImageReference
default:
return nil, fmt.Errorf("powershell tasks unsupported")
}
return containerRuntime.PullImage(ctx, ref)
}