relay-flow 0.2.7-alpha → 0.2.8-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -7
- package/cmd/relay-flow/commands_test.go +82 -11
- package/cmd/relay-flow/main.go +18 -86
- package/cmd/relay-flow/repo_registration.go +235 -0
- package/cmd/relay-flow/serve.go +2 -2
- package/examples/config-reference.yaml +7 -0
- package/internal/harness/opencode/opencode_test.go +1 -1
- package/internal/harness/opencode/repo_setup.go +1 -1
- package/internal/repo/service.go +13 -0
- package/internal/repo/service_test.go +14 -1
- package/internal/server/api_test.go +46 -0
- package/internal/server/client.go +30 -2
- package/internal/server/fixture_test.go +20 -16
- package/internal/server/server.go +39 -4
- package/internal/task/beads/beads.go +7 -2
- package/internal/task/beads/beads_test.go +13 -0
- package/internal/task/factory.go +9 -7
- package/internal/task/jira/auth_test.go +9 -1
- package/internal/task/jira/filters_test.go +2 -2
- package/internal/task/jira/helpers_test.go +13 -0
- package/internal/task/jira/jira.go +233 -44
- package/internal/task/jira/lifecycle_inheritance_test.go +5 -5
- package/internal/task/jira/rest/client.go +73 -31
- package/internal/task/jira/rest/client_test.go +25 -0
- package/internal/task/jira/status_defaults_test.go +134 -0
- package/internal/task/jira/templates_test.go +2 -2
- package/internal/task/jira/transition_defaults_test.go +8 -12
- package/internal/task/jira/validation_test.go +3 -1
- package/internal/task/registration.go +59 -0
- package/package.json +1 -1
|
@@ -264,7 +264,10 @@ func (errInvalidRepo) Error() string { return "invalid repo" }
|
|
|
264
264
|
|
|
265
265
|
func TestRegisterAtomicallyPersists(t *testing.T) {
|
|
266
266
|
fx := newServiceFixture(t, &fakeRunnerDiscovery{})
|
|
267
|
-
|
|
267
|
+
statusDefaults := map[string]any{"start": "Open", "work": "Working", "end": "Closed"}
|
|
268
|
+
if _, err := fx.svc.Register(context.Background(), repo.RegisterInput{Name: "payments", Path: "/srv/payments", TaskConfig: config.RawValues{
|
|
269
|
+
"project": "PAY", "component": "api", "statusDefaults": statusDefaults,
|
|
270
|
+
}}); err != nil {
|
|
268
271
|
t.Fatal(err)
|
|
269
272
|
}
|
|
270
273
|
cfg, err := config.LoadMachine(fx.cfgPath)
|
|
@@ -278,6 +281,16 @@ func TestRegisterAtomicallyPersists(t *testing.T) {
|
|
|
278
281
|
if r.TaskConfig["project"] != "PAY" {
|
|
279
282
|
t.Fatalf("repo taskConfig not persisted: %+v", r.TaskConfig)
|
|
280
283
|
}
|
|
284
|
+
var gotDefaults map[string]any
|
|
285
|
+
switch values := r.TaskConfig["statusDefaults"].(type) {
|
|
286
|
+
case map[string]any:
|
|
287
|
+
gotDefaults = values
|
|
288
|
+
case config.RawValues:
|
|
289
|
+
gotDefaults = map[string]any(values)
|
|
290
|
+
}
|
|
291
|
+
if gotDefaults == nil || gotDefaults["start"] != "Open" || gotDefaults["work"] != "Working" || gotDefaults["end"] != "Closed" {
|
|
292
|
+
t.Fatalf("repo statusDefaults not persisted: %#v", r.TaskConfig["statusDefaults"])
|
|
293
|
+
}
|
|
281
294
|
}
|
|
282
295
|
|
|
283
296
|
func TestRegisterSetsUpHarnessRepo(t *testing.T) {
|
|
@@ -2,15 +2,19 @@ package server_test
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"bytes"
|
|
5
|
+
"context"
|
|
5
6
|
"encoding/json"
|
|
6
7
|
"fmt"
|
|
7
8
|
"io"
|
|
8
9
|
"net/http"
|
|
10
|
+
"path/filepath"
|
|
9
11
|
"strings"
|
|
10
12
|
"testing"
|
|
11
13
|
"time"
|
|
12
14
|
|
|
15
|
+
"github.com/rajpopat27/relay-flow/internal/config"
|
|
13
16
|
"github.com/rajpopat27/relay-flow/internal/run"
|
|
17
|
+
"github.com/rajpopat27/relay-flow/internal/server"
|
|
14
18
|
"github.com/rajpopat27/relay-flow/internal/task"
|
|
15
19
|
"github.com/rajpopat27/relay-flow/internal/workflow"
|
|
16
20
|
)
|
|
@@ -287,6 +291,48 @@ func TestRunEndpointsExposeRetryDetails(t *testing.T) {
|
|
|
287
291
|
}
|
|
288
292
|
}
|
|
289
293
|
|
|
294
|
+
func TestRepoTaskFieldsSupportsInitialGetAndDependentPost(t *testing.T) {
|
|
295
|
+
fake := &fakeServices{}
|
|
296
|
+
c, cleanup := startHandler(t, fake)
|
|
297
|
+
defer cleanup()
|
|
298
|
+
|
|
299
|
+
code, env := do(t, c, http.MethodGet, "http://relay/repos/task-fields", nil)
|
|
300
|
+
if code != http.StatusOK || !env.OK || !bytes.Contains(env.Data, []byte(`"fields"`)) {
|
|
301
|
+
t.Fatalf("GET /repos/task-fields: code=%d env=%+v", code, env)
|
|
302
|
+
}
|
|
303
|
+
code, env = do(t, c, http.MethodPost, "http://relay/repos/task-fields", []byte(`{"values":{"project":"PAY"}}`))
|
|
304
|
+
if code != http.StatusOK || !env.OK || len(fake.registrationValues) != 2 {
|
|
305
|
+
t.Fatalf("POST /repos/task-fields: code=%d env=%+v values=%v", code, env, fake.registrationValues)
|
|
306
|
+
}
|
|
307
|
+
if fake.registrationValues[1]["project"] != "PAY" {
|
|
308
|
+
t.Fatalf("dependent registration values = %#v", fake.registrationValues[1])
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
func TestClientRepoRegistrationFieldsUsesGetThenPost(t *testing.T) {
|
|
313
|
+
fake := &fakeServices{}
|
|
314
|
+
dir := t.TempDir()
|
|
315
|
+
_, cleanup := startHandlerOnSocket(t, dir, fake)
|
|
316
|
+
defer cleanup()
|
|
317
|
+
client := server.NewClient(filepath.Join(dir, "server.sock"))
|
|
318
|
+
keys, err := client.RepoTaskFields(context.Background())
|
|
319
|
+
if err != nil || len(keys) != 2 || keys[0] != "project" || keys[1] != "component" {
|
|
320
|
+
t.Fatalf("documented task fields = %v, err=%v", keys, err)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
initial, err := client.RepoRegistrationFields(context.Background(), nil)
|
|
324
|
+
if err != nil || len(initial.Fields) != 2 {
|
|
325
|
+
t.Fatalf("initial registration fields = %#v, err=%v", initial, err)
|
|
326
|
+
}
|
|
327
|
+
dependent, err := client.RepoRegistrationFields(context.Background(), config.RawValues{"project": "PAY"})
|
|
328
|
+
if err != nil || len(dependent.Fields) != 2 {
|
|
329
|
+
t.Fatalf("dependent registration fields = %#v, err=%v", dependent, err)
|
|
330
|
+
}
|
|
331
|
+
if len(fake.registrationValues) != 3 || fake.registrationValues[0] != nil || fake.registrationValues[1] != nil || fake.registrationValues[2]["project"] != "PAY" {
|
|
332
|
+
t.Fatalf("registration request values = %#v", fake.registrationValues)
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
290
336
|
func TestRepoOperations(t *testing.T) {
|
|
291
337
|
c, cleanup := startHandler(t, &fakeServices{})
|
|
292
338
|
defer cleanup()
|
|
@@ -10,9 +10,11 @@ import (
|
|
|
10
10
|
"net/http"
|
|
11
11
|
"net/url"
|
|
12
12
|
|
|
13
|
+
"github.com/rajpopat27/relay-flow/internal/config"
|
|
13
14
|
"github.com/rajpopat27/relay-flow/internal/repo"
|
|
14
15
|
"github.com/rajpopat27/relay-flow/internal/run"
|
|
15
16
|
"github.com/rajpopat27/relay-flow/internal/runner"
|
|
17
|
+
"github.com/rajpopat27/relay-flow/internal/task"
|
|
16
18
|
"github.com/rajpopat27/relay-flow/internal/workflow"
|
|
17
19
|
)
|
|
18
20
|
|
|
@@ -134,8 +136,7 @@ func (c *Client) DiscoverRepos(ctx context.Context) ([]runner.RepoCandidate, err
|
|
|
134
136
|
return out, nil
|
|
135
137
|
}
|
|
136
138
|
|
|
137
|
-
// RepoTaskFields returns the
|
|
138
|
-
// GET /repos/task-fields (server wraps the list as {"fields": [...]}).
|
|
139
|
+
// RepoTaskFields returns the documented initial required-key metadata.
|
|
139
140
|
func (c *Client) RepoTaskFields(ctx context.Context) ([]string, error) {
|
|
140
141
|
var out struct {
|
|
141
142
|
Fields []string `json:"fields"`
|
|
@@ -146,6 +147,33 @@ func (c *Client) RepoTaskFields(ctx context.Context) ([]string, error) {
|
|
|
146
147
|
return out.Fields, nil
|
|
147
148
|
}
|
|
148
149
|
|
|
150
|
+
// RepoRegistrationFields returns task-plugin-owned repository prompts. Values
|
|
151
|
+
// are flat registration inputs so plugins can discover dependent choices (for
|
|
152
|
+
// example project statuses after project is selected). Initial discovery uses
|
|
153
|
+
// the documented GET endpoint; dependent discovery uses POST.
|
|
154
|
+
func (c *Client) RepoRegistrationFields(ctx context.Context, values config.RawValues) (task.Registration, error) {
|
|
155
|
+
if len(values) == 0 {
|
|
156
|
+
var out struct {
|
|
157
|
+
Registration task.Registration `json:"registration"`
|
|
158
|
+
}
|
|
159
|
+
if err := c.call(ctx, http.MethodGet, "/repos/task-fields", nil, &out); err != nil {
|
|
160
|
+
return task.Registration{}, err
|
|
161
|
+
}
|
|
162
|
+
return out.Registration, nil
|
|
163
|
+
}
|
|
164
|
+
payload, err := json.Marshal(struct {
|
|
165
|
+
Values config.RawValues `json:"values,omitempty"`
|
|
166
|
+
}{Values: values})
|
|
167
|
+
if err != nil {
|
|
168
|
+
return task.Registration{}, err
|
|
169
|
+
}
|
|
170
|
+
var out task.Registration
|
|
171
|
+
if err := c.call(ctx, http.MethodPost, "/repos/task-fields", payload, &out); err != nil {
|
|
172
|
+
return task.Registration{}, err
|
|
173
|
+
}
|
|
174
|
+
return out, nil
|
|
175
|
+
}
|
|
176
|
+
|
|
149
177
|
// RegisterRepo registers a repo by name/path with optional task config.
|
|
150
178
|
func (c *Client) RegisterRepo(ctx context.Context, input repo.RegisterInput) (repo.Info, error) {
|
|
151
179
|
payload, _ := json.Marshal(input)
|
|
@@ -12,10 +12,12 @@ import (
|
|
|
12
12
|
"path/filepath"
|
|
13
13
|
"testing"
|
|
14
14
|
|
|
15
|
+
"github.com/rajpopat27/relay-flow/internal/config"
|
|
15
16
|
"github.com/rajpopat27/relay-flow/internal/repo"
|
|
16
17
|
"github.com/rajpopat27/relay-flow/internal/run"
|
|
17
18
|
"github.com/rajpopat27/relay-flow/internal/runner"
|
|
18
19
|
"github.com/rajpopat27/relay-flow/internal/server"
|
|
20
|
+
"github.com/rajpopat27/relay-flow/internal/task"
|
|
19
21
|
"github.com/rajpopat27/relay-flow/internal/workflow"
|
|
20
22
|
)
|
|
21
23
|
|
|
@@ -23,20 +25,21 @@ import (
|
|
|
23
25
|
// seams. activeWorkflows seeds workflows with an active run (drives 409);
|
|
24
26
|
// failRepos forces a 500; slowReport simulates a long-running report call.
|
|
25
27
|
type fakeServices struct {
|
|
26
|
-
activeWorkflows
|
|
27
|
-
failRepos
|
|
28
|
-
slowReport
|
|
29
|
-
workflows
|
|
30
|
-
repos
|
|
31
|
-
runs
|
|
32
|
-
shutdownCh
|
|
33
|
-
registrations
|
|
34
|
-
runtimeAck
|
|
35
|
-
processedReports
|
|
36
|
-
submittedReports
|
|
37
|
-
restartRun
|
|
38
|
-
restartErr
|
|
39
|
-
restarts
|
|
28
|
+
activeWorkflows map[string]bool
|
|
29
|
+
failRepos bool
|
|
30
|
+
slowReport chan struct{}
|
|
31
|
+
workflows map[string]*workflow.Workflow
|
|
32
|
+
repos map[string]repo.Info
|
|
33
|
+
runs []run.Run
|
|
34
|
+
shutdownCh chan struct{}
|
|
35
|
+
registrations []run.NodeRuntimeRegistration
|
|
36
|
+
runtimeAck run.NodeRuntimeRegistrationAck
|
|
37
|
+
processedReports map[string]bool
|
|
38
|
+
submittedReports int
|
|
39
|
+
restartRun run.Run
|
|
40
|
+
restartErr error
|
|
41
|
+
restarts []string
|
|
42
|
+
registrationValues []config.RawValues
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
func (f *fakeServices) SubmitWorkflow(_ context.Context, yaml []byte) (*workflow.Workflow, error) {
|
|
@@ -152,8 +155,9 @@ func (f *fakeServices) DiscoverRepos(context.Context) ([]runner.RepoCandidate, e
|
|
|
152
155
|
return []runner.RepoCandidate{{Name: "payments", Path: "/srv/payments"}}, nil
|
|
153
156
|
}
|
|
154
157
|
|
|
155
|
-
func (f *fakeServices)
|
|
156
|
-
|
|
158
|
+
func (f *fakeServices) TaskRegistrationFields(_ context.Context, values config.RawValues) ([]task.RegistrationField, error) {
|
|
159
|
+
f.registrationValues = append(f.registrationValues, values)
|
|
160
|
+
return []task.RegistrationField{{Key: "project", Title: "Project"}, {Key: "component", Title: "Component", Derived: true}}, nil
|
|
157
161
|
}
|
|
158
162
|
|
|
159
163
|
func (f *fakeServices) RegisterRepo(_ context.Context, input repo.RegisterInput) (repo.Info, error) {
|
|
@@ -12,9 +12,11 @@ import (
|
|
|
12
12
|
"net/http"
|
|
13
13
|
"strings"
|
|
14
14
|
|
|
15
|
+
"github.com/rajpopat27/relay-flow/internal/config"
|
|
15
16
|
"github.com/rajpopat27/relay-flow/internal/repo"
|
|
16
17
|
"github.com/rajpopat27/relay-flow/internal/run"
|
|
17
18
|
"github.com/rajpopat27/relay-flow/internal/runner"
|
|
19
|
+
"github.com/rajpopat27/relay-flow/internal/task"
|
|
18
20
|
"github.com/rajpopat27/relay-flow/internal/workflow"
|
|
19
21
|
)
|
|
20
22
|
|
|
@@ -41,7 +43,7 @@ type Deps interface {
|
|
|
41
43
|
|
|
42
44
|
// Repos
|
|
43
45
|
DiscoverRepos(ctx context.Context) ([]runner.RepoCandidate, error)
|
|
44
|
-
|
|
46
|
+
TaskRegistrationFields(ctx context.Context, values config.RawValues) ([]task.RegistrationField, error)
|
|
45
47
|
RegisterRepo(ctx context.Context, input repo.RegisterInput) (repo.Info, error)
|
|
46
48
|
ListRepos(ctx context.Context) ([]repo.Info, error)
|
|
47
49
|
GetRepo(ctx context.Context, name string) (repo.Info, error)
|
|
@@ -246,15 +248,48 @@ func (s *server) handleReposDiscover(w http.ResponseWriter, r *http.Request) {
|
|
|
246
248
|
}
|
|
247
249
|
|
|
248
250
|
func (s *server) handleRepoTaskFields(w http.ResponseWriter, r *http.Request) {
|
|
249
|
-
if
|
|
251
|
+
if r.Method == http.MethodGet {
|
|
252
|
+
fields, err := s.deps.TaskRegistrationFields(r.Context(), nil)
|
|
253
|
+
if err != nil {
|
|
254
|
+
mapErr(w, err)
|
|
255
|
+
return
|
|
256
|
+
}
|
|
257
|
+
keys := make([]string, 0, len(fields))
|
|
258
|
+
for _, field := range fields {
|
|
259
|
+
keys = append(keys, field.Key)
|
|
260
|
+
}
|
|
261
|
+
// Keep the documented fields list for callers that only need the
|
|
262
|
+
// required keys, and include plugin-owned metadata for the CLI's
|
|
263
|
+
// initial prompt construction.
|
|
264
|
+
writeOK(w, http.StatusOK, map[string]any{
|
|
265
|
+
"fields": keys,
|
|
266
|
+
"registration": task.Registration{Fields: fields},
|
|
267
|
+
})
|
|
268
|
+
return
|
|
269
|
+
}
|
|
270
|
+
if !methodOnly(w, r, http.MethodPost) {
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
body, err := readBody(r)
|
|
274
|
+
if err != nil {
|
|
275
|
+
writeErr(w, http.StatusBadRequest, "invalid", err.Error())
|
|
250
276
|
return
|
|
251
277
|
}
|
|
252
|
-
|
|
278
|
+
var payload struct {
|
|
279
|
+
Values config.RawValues `json:"values,omitempty"`
|
|
280
|
+
}
|
|
281
|
+
if len(strings.TrimSpace(string(body))) > 0 {
|
|
282
|
+
if err := decodeStrict(body, &payload); err != nil {
|
|
283
|
+
writeErr(w, http.StatusBadRequest, "invalid", err.Error())
|
|
284
|
+
return
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
fields, err := s.deps.TaskRegistrationFields(r.Context(), payload.Values)
|
|
253
288
|
if err != nil {
|
|
254
289
|
mapErr(w, err)
|
|
255
290
|
return
|
|
256
291
|
}
|
|
257
|
-
writeOK(w, http.StatusOK,
|
|
292
|
+
writeOK(w, http.StatusOK, task.Registration{Fields: fields})
|
|
258
293
|
}
|
|
259
294
|
|
|
260
295
|
func (s *server) handleRepos(w http.ResponseWriter, r *http.Request) {
|
|
@@ -81,10 +81,15 @@ func DefaultConfig() config.RawValues {
|
|
|
81
81
|
}}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
func registrationFields(context.Context, config.RawValues) ([]task.RegistrationField, error) {
|
|
85
|
+
return []task.RegistrationField{{Key: "beadsDir", Title: "Beads workspace"}}, nil
|
|
86
|
+
}
|
|
87
|
+
|
|
84
88
|
func init() {
|
|
85
89
|
task.Register("beads", task.Factory{
|
|
86
|
-
RequiredRepoKeys:
|
|
87
|
-
|
|
90
|
+
RequiredRepoKeys: func() []string { return []string{"beadsDir"} },
|
|
91
|
+
RegistrationFields: registrationFields,
|
|
92
|
+
TaskScopeKey: beadsTaskScopeKey,
|
|
88
93
|
RegistrationKey: func(spec task.RepoRegistrationSpec) (string, error) {
|
|
89
94
|
label, err := RepositoryLabel(spec.Name)
|
|
90
95
|
if err != nil {
|
|
@@ -29,6 +29,19 @@ func TestBeadsFactoryIsRegisteredWithBeadsDirRequirement(t *testing.T) {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
func TestBeadsRegistrationDoesNotExposeJiraStatusFields(t *testing.T) {
|
|
33
|
+
fields, err := task.RegistrationFields(context.Background(), "beads", nil)
|
|
34
|
+
if err != nil {
|
|
35
|
+
t.Fatal(err)
|
|
36
|
+
}
|
|
37
|
+
if len(fields) != 1 || fields[0].Key != "beadsDir" {
|
|
38
|
+
t.Fatalf("registration fields = %#v, want only beadsDir", fields)
|
|
39
|
+
}
|
|
40
|
+
if len(fields[0].Options) != 0 || fields[0].Default != "" {
|
|
41
|
+
t.Fatalf("Beads registration field unexpectedly has status choices: %#v", fields[0])
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
32
45
|
func TestBeadsConfigRejectsUnknownFields(t *testing.T) {
|
|
33
46
|
for _, field := range []string{"unknownField", "project", "component"} {
|
|
34
47
|
t.Run(field, func(t *testing.T) {
|
package/internal/task/factory.go
CHANGED
|
@@ -36,13 +36,15 @@ type RepoRegistrationSpec struct {
|
|
|
36
36
|
// the complete registration identity when a plugin permits sharing a
|
|
37
37
|
// physical scope with distinct logical repositories.
|
|
38
38
|
type Factory struct {
|
|
39
|
-
RequiredRepoKeys
|
|
40
|
-
TaskScopeKey
|
|
41
|
-
RegistrationKey
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
RequiredRepoKeys func() []string
|
|
40
|
+
TaskScopeKey func(rootConfig, repoConfig config.RawValues) (string, error)
|
|
41
|
+
RegistrationKey func(RepoRegistrationSpec) (string, error)
|
|
42
|
+
RegistrationFields func(context.Context, config.RawValues) ([]RegistrationField, error)
|
|
43
|
+
ValidateRegistration func(context.Context, RepoRegistrationSpec) error
|
|
44
|
+
Auth func(context.Context, []string, io.Reader) error
|
|
45
|
+
DefaultConfig func() config.RawValues
|
|
46
|
+
ValidateTextConfig func(config.RawValues) error
|
|
47
|
+
New func(context.Context, RepoSpec) (System, error)
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
var (
|
|
@@ -75,7 +75,15 @@ func TestAuthWritesLoadsAndNewUsesJiraOwnedCredentials(t *testing.T) {
|
|
|
75
75
|
}
|
|
76
76
|
if _, err := task.New(context.Background(), "jira", task.RepoSpec{
|
|
77
77
|
Name: "payments", RootConfig: machine.TaskConfig,
|
|
78
|
-
RepoConfig: config.RawValues{
|
|
78
|
+
RepoConfig: config.RawValues{
|
|
79
|
+
"project": "PAY",
|
|
80
|
+
"component": "api",
|
|
81
|
+
"statusDefaults": map[string]any{
|
|
82
|
+
"start": defaultStartParentStatus,
|
|
83
|
+
"work": defaultWorkTaskStatus,
|
|
84
|
+
"end": defaultEndParentStatus,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
79
87
|
}); err != nil {
|
|
80
88
|
t.Fatalf("task.New did not load Jira-owned credentials: %v", err)
|
|
81
89
|
}
|
|
@@ -284,7 +284,7 @@ func TestCompileFilterDoesNotUseEffectiveAssigneeAsFilter(t *testing.T) {
|
|
|
284
284
|
sys, err := newSystem(context.Background(), &fakeClient{fake: &fakeJira{}}, task.RepoSpec{
|
|
285
285
|
Name: "payments",
|
|
286
286
|
RootConfig: config.RawValues{"assignee": "root@example.com"},
|
|
287
|
-
RepoConfig: config.RawValues{"
|
|
287
|
+
RepoConfig: testRepoConfig(config.RawValues{"assignee": "Repo.Bot@Example.com"}),
|
|
288
288
|
})
|
|
289
289
|
if err != nil {
|
|
290
290
|
t.Fatal(err)
|
|
@@ -304,7 +304,7 @@ func TestCompileFilterWorkflowAssigneesOverrideEffectiveAssignee(t *testing.T) {
|
|
|
304
304
|
sys, err := newSystem(context.Background(), &fakeClient{fake: &fakeJira{}}, task.RepoSpec{
|
|
305
305
|
Name: "payments",
|
|
306
306
|
RootConfig: config.RawValues{"assignee": "root@example.com"},
|
|
307
|
-
RepoConfig:
|
|
307
|
+
RepoConfig: testRepoConfig(nil),
|
|
308
308
|
})
|
|
309
309
|
if err != nil {
|
|
310
310
|
t.Fatal(err)
|
|
@@ -3,6 +3,7 @@ package jira
|
|
|
3
3
|
import (
|
|
4
4
|
"context"
|
|
5
5
|
|
|
6
|
+
"github.com/rajpopat27/relay-flow/internal/config"
|
|
6
7
|
"github.com/rajpopat27/relay-flow/internal/task"
|
|
7
8
|
"github.com/rajpopat27/relay-flow/internal/task/jira/rest"
|
|
8
9
|
)
|
|
@@ -67,6 +68,18 @@ func (notFakedError) Error() string { return "not faked" }
|
|
|
67
68
|
|
|
68
69
|
var errNotFaked = notFakedError{}
|
|
69
70
|
|
|
71
|
+
func testStatusDefaults() config.RawValues {
|
|
72
|
+
return config.RawValues{"statusDefaults": map[string]any{
|
|
73
|
+
"start": defaultStartParentStatus,
|
|
74
|
+
"work": defaultWorkTaskStatus,
|
|
75
|
+
"end": defaultEndParentStatus,
|
|
76
|
+
}}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
func testRepoConfig(values config.RawValues) config.RawValues {
|
|
80
|
+
return config.Merge(config.RawValues{"project": "PAY", "component": "api"}, testStatusDefaults(), values)
|
|
81
|
+
}
|
|
82
|
+
|
|
70
83
|
// newSystemForTest builds the adapter around the test-local REST seam.
|
|
71
84
|
func newSystemForTest(fake *fakeJira) (task.System, error) {
|
|
72
85
|
return newSystemForCLI(&fakeClient{fake: fake})
|