+89
knotserver/internal.go
+89
knotserver/internal.go
···
6
6
"log/slog"
7
7
"net/http"
8
8
"path/filepath"
9
+
"strings"
9
10
11
+
securejoin "github.com/cyphar/filepath-securejoin"
10
12
"github.com/go-chi/chi/v5"
11
13
"github.com/go-chi/chi/v5/middleware"
12
14
"tangled.sh/tangled.sh/core/api/tangled"
···
15
17
"tangled.sh/tangled.sh/core/knotserver/git"
16
18
"tangled.sh/tangled.sh/core/knotserver/notifier"
17
19
"tangled.sh/tangled.sh/core/rbac"
20
+
"tangled.sh/tangled.sh/core/workflow"
18
21
)
19
22
20
23
type InternalHandle struct {
···
92
95
l.Error("failed to insert op", "err", err, "line", line, "did", gitUserDid, "repo", gitRelativeDir)
93
96
// non-fatal
94
97
}
98
+
99
+
err = h.triggerPipeline(line, gitUserDid, repoDid, repoName)
100
+
if err != nil {
101
+
l.Error("failed to trigger pipeline", "err", err, "line", line, "did", gitUserDid, "repo", gitRelativeDir)
102
+
// non-fatal
103
+
}
95
104
}
96
105
}
97
106
···
112
121
event := db.Event{
113
122
Rkey: TID(),
114
123
Nsid: tangled.GitRefUpdateNSID,
124
+
EventJson: string(eventJson),
125
+
}
126
+
127
+
return h.db.InsertEvent(event, h.n)
128
+
}
129
+
130
+
func (h *InternalHandle) triggerPipeline(line git.PostReceiveLine, gitUserDid, repoDid, repoName string) error {
131
+
const (
132
+
WorkflowDir = ".tangled/workflows"
133
+
)
134
+
135
+
didSlashRepo, err := securejoin.SecureJoin(repoDid, repoName)
136
+
if err != nil {
137
+
return err
138
+
}
139
+
140
+
repoPath, err := securejoin.SecureJoin(h.c.Repo.ScanPath, didSlashRepo)
141
+
if err != nil {
142
+
return err
143
+
}
144
+
145
+
gr, err := git.Open(repoPath, line.Ref)
146
+
if err != nil {
147
+
return err
148
+
}
149
+
150
+
workflowDir, err := gr.FileTree(context.Background(), WorkflowDir)
151
+
if err != nil {
152
+
return err
153
+
}
154
+
155
+
var pipeline workflow.Pipeline
156
+
for _, e := range workflowDir {
157
+
if !e.IsFile {
158
+
continue
159
+
}
160
+
161
+
fpath := filepath.Join(WorkflowDir, e.Name)
162
+
contents, err := gr.RawContent(fpath)
163
+
if err != nil {
164
+
continue
165
+
}
166
+
167
+
wf, err := workflow.FromFile(e.Name, contents)
168
+
if err != nil {
169
+
// TODO: log here, respond to client that is pushing
170
+
continue
171
+
}
172
+
173
+
pipeline = append(pipeline, wf)
174
+
}
175
+
176
+
trigger := tangled.Pipeline_PushTriggerData{
177
+
Ref: line.Ref,
178
+
OldSha: line.OldSha,
179
+
NewSha: line.NewSha,
180
+
}
181
+
182
+
compiler := workflow.Compiler{
183
+
Trigger: tangled.Pipeline_TriggerMetadata{
184
+
Kind: string(workflow.TriggerKindPush),
185
+
Push: &trigger,
186
+
Repo: &tangled.Pipeline_TriggerRepo{
187
+
Did: repoDid,
188
+
Knot: h.c.Server.Hostname,
189
+
Repo: repoName,
190
+
},
191
+
},
192
+
}
193
+
194
+
// TODO: send the diagnostics back to the user here via stderr
195
+
cp := compiler.Compile(pipeline)
196
+
eventJson, err := json.Marshal(cp)
197
+
if err != nil {
198
+
return err
199
+
}
200
+
201
+
event := db.Event{
202
+
Rkey: TID(),
203
+
Nsid: tangled.PipelineNSID,
115
204
EventJson: string(eventJson),
116
205
}
117
206