Skip to content

Commit 911738d

Browse files
committed
pkg/workflows/sdk: add WorkflowSpec.FormatChart for mermaid flowcharts
1 parent dd59341 commit 911738d

16 files changed

+754
-154
lines changed

Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,7 @@ lint-workspace:
4747

4848
lint:
4949
@./script/lint.sh $(GOLANGCI_LINT_VERSION) "$(GOLANGCI_LINT_COMMON_OPTS)" $(GOLANGCI_LINT_DIRECTORY) "--new-from-rev=origin/main"
50+
51+
.PHONY: test-quiet
52+
test-quiet:
53+
go test ./... | grep -v "\[no test files\]" | grep -v "\(cached\)"

go.mod

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
module github.com/smartcontractkit/chainlink-common
22

3-
go 1.22.0
4-
5-
toolchain go1.22.7
3+
go 1.23
64

75
require (
86
github.com/andybalholm/brotli v1.1.0

pkg/capabilities/capabilities.go

+21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package capabilities
22

33
import (
4+
"cmp"
45
"context"
56
"fmt"
67
"regexp"
@@ -53,6 +54,26 @@ func (c CapabilityType) IsValid() error {
5354
return fmt.Errorf("invalid capability type: %s", c)
5455
}
5556

57+
func (c CapabilityType) cmpOrder() int {
58+
switch c {
59+
case CapabilityTypeTrigger:
60+
return 0
61+
case CapabilityTypeAction:
62+
return 1
63+
case CapabilityTypeConsensus:
64+
return 2
65+
case CapabilityTypeTarget:
66+
return 3
67+
case CapabilityTypeUnknown:
68+
return 4
69+
default:
70+
return 5
71+
}
72+
}
73+
func (c CapabilityType) Compare(c2 CapabilityType) int {
74+
return cmp.Compare(c.cmpOrder(), c2.cmpOrder())
75+
}
76+
5677
// CapabilityResponse is a struct for the Execute response of a capability.
5778
type CapabilityResponse struct {
5879
Value *values.Map

pkg/workflows/models_yaml_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ var transformJSON = cmp.FilterValues(func(x, y []byte) bool {
4949
return out
5050
}))
5151

52-
func TestWorkflowSpecMarshalling(t *testing.T) {
52+
func TestWorkflowSpecYamlMarshalling(t *testing.T) {
5353
t.Parallel()
5454
fixtureReader := yamlFixtureReaderBytes(t, "marshalling")
5555

pkg/workflows/sdk/builder_test.go

+1-76
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"github.com/stretchr/testify/require"
88
"sigs.k8s.io/yaml"
99

10-
"github.com/smartcontractkit/chainlink-common/pkg/capabilities"
1110
ocr3 "github.com/smartcontractkit/chainlink-common/pkg/capabilities/consensus/ocr3/ocr3cap"
1211
"github.com/smartcontractkit/chainlink-common/pkg/capabilities/targets/chainwriter"
1312
"github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers/streams"
@@ -205,81 +204,7 @@ func TestBuilder_ValidSpec(t *testing.T) {
205204
actual, err := factory.Spec()
206205
require.NoError(t, err)
207206

208-
expected := sdk.WorkflowSpec{
209-
Name: "notccipethsep",
210-
Owner: "0x00000000000000000000000000000000000000aa",
211-
Triggers: []sdk.StepDefinition{
212-
{
213-
214-
Ref: "trigger",
215-
Inputs: sdk.StepInputs{},
216-
Config: map[string]any{"maxFrequencyMs": 5000},
217-
CapabilityType: capabilities.CapabilityTypeTrigger,
218-
},
219-
},
220-
Actions: make([]sdk.StepDefinition, 0),
221-
Consensus: []sdk.StepDefinition{
222-
{
223-
224-
Ref: "data-feeds-report",
225-
Inputs: sdk.StepInputs{
226-
Mapping: map[string]any{"observations": []map[string]any{
227-
{
228-
"Metadata": map[string]any{
229-
"MinRequiredSignatures": 1,
230-
"Signers": []string{"$(trigger.outputs.Metadata.Signer)"},
231-
},
232-
"Payload": []map[string]any{
233-
{
234-
"BenchmarkPrice": "$(trigger.outputs.Payload.BuyPrice)",
235-
"FeedID": anyFakeFeedID,
236-
"FullReport": "$(trigger.outputs.Payload.FullReport)",
237-
"ObservationTimestamp": "$(trigger.outputs.Payload.ObservationTimestamp)",
238-
"ReportContext": "$(trigger.outputs.Payload.ReportContext)",
239-
"Signatures": []string{"$(trigger.outputs.Payload.Signature)"},
240-
},
241-
},
242-
"Timestamp": "$(trigger.outputs.Timestamp)",
243-
},
244-
}},
245-
},
246-
Config: map[string]any{
247-
"aggregation_config": ocr3.DataFeedsConsensusConfigAggregationConfig{
248-
AllowedPartialStaleness: "0.5",
249-
Feeds: map[string]ocr3.FeedValue{
250-
anyFakeFeedID: {
251-
Deviation: "0.5",
252-
Heartbeat: 3600,
253-
},
254-
},
255-
},
256-
"aggregation_method": "data_feeds",
257-
"encoder": "EVM",
258-
"encoder_config": ocr3.EncoderConfig{
259-
"Abi": "(bytes32 FeedID, uint224 Price, uint32 Timestamp)[] Reports",
260-
},
261-
"report_id": "0001",
262-
},
263-
CapabilityType: capabilities.CapabilityTypeConsensus,
264-
},
265-
},
266-
Targets: []sdk.StepDefinition{
267-
{
268-
269-
Inputs: sdk.StepInputs{
270-
Mapping: map[string]any{"signed_report": "$(data-feeds-report.outputs)"},
271-
},
272-
Config: map[string]any{
273-
"address": "0xE0082363396985ae2FdcC3a9F816A586Eed88416",
274-
"deltaStage": "45s",
275-
"schedule": "oneAtATime",
276-
},
277-
CapabilityType: capabilities.CapabilityTypeTarget,
278-
},
279-
},
280-
}
281-
282-
testutils.AssertWorkflowSpec(t, expected, actual)
207+
testutils.AssertWorkflowSpec(t, notStreamSepoliaWorkflowSpec, actual)
283208
})
284209

285210
t.Run("duplicate names causes errors", func(t *testing.T) {

pkg/workflows/sdk/compute_test.go

+2-68
Original file line numberDiff line numberDiff line change
@@ -39,74 +39,8 @@ func TestCompute(t *testing.T) {
3939

4040
spec, err2 := workflow.Spec()
4141
require.NoError(t, err2)
42-
expectedSpec := sdk.WorkflowSpec{
43-
Name: "name",
44-
Owner: "owner",
45-
Triggers: []sdk.StepDefinition{
46-
{
47-
48-
Ref: "trigger",
49-
Inputs: sdk.StepInputs{},
50-
Config: map[string]any{"maxFrequencyMs": 5000},
51-
CapabilityType: capabilities.CapabilityTypeTrigger,
52-
},
53-
},
54-
Actions: []sdk.StepDefinition{
55-
{
56-
57-
Ref: "Compute",
58-
Inputs: sdk.StepInputs{
59-
Mapping: map[string]any{"Arg0": "$(trigger.outputs)"},
60-
},
61-
Config: map[string]any{
62-
"binary": "$(ENV.binary)",
63-
"config": "$(ENV.config)",
64-
},
65-
CapabilityType: capabilities.CapabilityTypeAction,
66-
},
67-
},
68-
Consensus: []sdk.StepDefinition{
69-
{
70-
71-
Ref: "data-feeds-report",
72-
Inputs: sdk.StepInputs{
73-
Mapping: map[string]any{"observations": "$(Compute.outputs.Value)"},
74-
},
75-
Config: map[string]any{
76-
"aggregation_config": ocr3.DataFeedsConsensusConfigAggregationConfig{
77-
AllowedPartialStaleness: "false",
78-
Feeds: map[string]ocr3.FeedValue{
79-
anyFakeFeedID: {
80-
Deviation: "0.5",
81-
Heartbeat: 3600,
82-
},
83-
},
84-
},
85-
"aggregation_method": "data_feeds",
86-
"encoder": ocr3.EncoderEVM,
87-
"encoder_config": ocr3.EncoderConfig{},
88-
"report_id": "0001",
89-
},
90-
CapabilityType: capabilities.CapabilityTypeConsensus,
91-
},
92-
},
93-
Targets: []sdk.StepDefinition{
94-
{
95-
96-
Inputs: sdk.StepInputs{
97-
Mapping: map[string]any{"signed_report": "$(data-feeds-report.outputs)"},
98-
},
99-
Config: map[string]any{
100-
"address": "0xE0082363396985ae2FdcC3a9F816A586Eed88416",
101-
"deltaStage": "45s",
102-
"schedule": "oneAtATime",
103-
},
104-
CapabilityType: capabilities.CapabilityTypeTarget,
105-
},
106-
},
107-
}
10842

109-
testutils.AssertWorkflowSpec(t, expectedSpec, spec)
43+
testutils.AssertWorkflowSpec(t, serialWorkflowSpec, spec)
11044
})
11145

11246
t.Run("compute runs the function and returns the value", func(t *testing.T) {
@@ -133,7 +67,7 @@ func TestCompute(t *testing.T) {
13367
func createWorkflow(fn func(_ sdk.Runtime, inputFeed notstreams.Feed) ([]streams.Feed, error)) *sdk.WorkflowSpecFactory {
13468
workflow := sdk.NewWorkflowSpecFactory(sdk.NewWorkflowParams{
13569
Owner: "owner",
136-
Name: "name",
70+
Name: "serial",
13771
})
13872

13973
trigger := notstreams.TriggerConfig{MaxFrequencyMs: 5000}.New(workflow)

pkg/workflows/sdk/helper_test.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package sdk
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func (w *WorkflowSpecFactory) MustSpec(t *testing.T) WorkflowSpec {
10+
t.Helper()
11+
s, err := w.Spec()
12+
require.NoError(t, err)
13+
return s
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# WorkflowSpec Charts
2+
3+
This directory contains WorkflowSpec chart golden files. They are validated against test data by TestWorkflowSpecFormatChart,
4+
and can be regenerated by passing the `-update` flag:
5+
```sh
6+
go test -run=TestWorkflowSpecFormatChart ./pkg/workflows/sdk/ -update
7+
```
8+
You can also invoke go:generate on package sdk, which will do the same.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
```mermaid
2+
flowchart
3+
4+
trigger[\"<b>trigger</b><br>trigger<br><i>(basic-test-trigger[at]1.0.0)</i>"/]
5+
6+
compute["<b>compute</b><br>action<br><i>(custom_compute[at]1.0.0)</i>"]
7+
get-bar -- Value --> compute
8+
get-baz -- Value --> compute
9+
get-foo -- Value --> compute
10+
11+
get-bar["<b>get-bar</b><br>action<br><i>(custom_compute[at]1.0.0)</i>"]
12+
trigger -- cool_output --> get-bar
13+
14+
get-baz["<b>get-baz</b><br>action<br><i>(custom_compute[at]1.0.0)</i>"]
15+
trigger -- cool_output --> get-baz
16+
17+
get-foo["<b>get-foo</b><br>action<br><i>(custom_compute[at]1.0.0)</i>"]
18+
trigger -- cool_output --> get-foo
19+
20+
consensus[["<b>consensus</b><br>consensus<br><i>(offchain_reporting[at]1.0.0)</i>"]]
21+
compute -- Value --> consensus
22+
23+
unnamed6[/"target<br><i>(id)</i>"\]
24+
consensus --> unnamed6
25+
26+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
```mermaid
2+
flowchart
3+
4+
trigger[\"<b>trigger</b><br>trigger<br><i>(notstreams[at]1.0.0)</i>"/]
5+
6+
data-feeds-report[["<b>data-feeds-report</b><br>consensus<br><i>(offchain_reporting[at]1.0.0)</i>"]]
7+
trigger -- Metadata.Signer<br>Payload.BuyPrice<br>Payload.FullReport<br>Payload.ObservationTimestamp<br>Payload.ReportContext<br>Payload.Signature<br>Timestamp --> data-feeds-report
8+
9+
unnamed2[/"target<br><i>(write_ethereum-testnet-sepolia[at]1.0.0)</i>"\]
10+
data-feeds-report --> unnamed2
11+
12+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
```mermaid
2+
flowchart
3+
4+
trigger-chain-event[\"<b>trigger-chain-event</b><br>trigger<br><i>(chain_reader[at]1.0.0)</i>"/]
5+
6+
compute-bar["<b>compute-bar</b><br>action<br><i>(custom_compute[at]1.0.0)</i>"]
7+
get-bar --> compute-bar
8+
9+
compute-foo["<b>compute-foo</b><br>action<br><i>(custom_compute[at]1.0.0)</i>"]
10+
get-foo --> compute-foo
11+
12+
get-bar["<b>get-bar</b><br>action<br><i>(http[at]1.0.0)</i>"]
13+
trigger-chain-event --> get-bar
14+
15+
get-foo["<b>get-foo</b><br>action<br><i>(http[at]1.0.0)</i>"]
16+
trigger-chain-event --> get-foo
17+
18+
read-token-price["<b>read-token-price</b><br>action<br><i>(chain_reader[at]1.0.0)</i>"]
19+
trigger-chain-event --> read-token-price
20+
21+
data-feeds-report[["<b>data-feeds-report</b><br>consensus<br><i>(offchain_reporting[at]1.0.0)</i>"]]
22+
compute-bar -- Value --> data-feeds-report
23+
compute-foo -- Value --> data-feeds-report
24+
read-token-price -- Value --> data-feeds-report
25+
26+
unnamed7[/"target<br><i>(write_ethereum-testnet-sepolia[at]1.0.0)</i>"\]
27+
data-feeds-report --> unnamed7
28+
29+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
```mermaid
2+
flowchart
3+
4+
trigger-chain-event[\"<b>trigger-chain-event</b><br>trigger<br><i>(chain_reader[at]1.0.0)</i>"/]
5+
6+
compute-bar["<b>compute-bar</b><br>action<br><i>(custom_compute[at]1.0.0)</i>"]
7+
get-bar --> compute-bar
8+
9+
compute-foo["<b>compute-foo</b><br>action<br><i>(custom_compute[at]1.0.0)</i>"]
10+
get-foo --> compute-foo
11+
12+
get-bar["<b>get-bar</b><br>action<br><i>(http[at]1.0.0)</i>"]
13+
compute-foo -..-> get-bar
14+
trigger-chain-event --> get-bar
15+
16+
get-foo["<b>get-foo</b><br>action<br><i>(http[at]1.0.0)</i>"]
17+
trigger-chain-event --> get-foo
18+
19+
read-token-price["<b>read-token-price</b><br>action<br><i>(chain_reader[at]1.0.0)</i>"]
20+
compute-bar -..-> read-token-price
21+
trigger-chain-event --> read-token-price
22+
23+
data-feeds-report[["<b>data-feeds-report</b><br>consensus<br><i>(offchain_reporting[at]1.0.0)</i>"]]
24+
compute-bar -- Value --> data-feeds-report
25+
compute-foo -- Value --> data-feeds-report
26+
read-token-price -- Value --> data-feeds-report
27+
28+
unnamed7[/"target<br><i>(write_ethereum-testnet-sepolia[at]1.0.0)</i>"\]
29+
data-feeds-report --> unnamed7
30+
31+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
```mermaid
2+
flowchart
3+
4+
trigger[\"<b>trigger</b><br>trigger<br><i>(notstreams[at]1.0.0)</i>"/]
5+
6+
Compute["<b>Compute</b><br>action<br><i>(custom_compute[at]1.0.0)</i>"]
7+
trigger --> Compute
8+
9+
data-feeds-report[["<b>data-feeds-report</b><br>consensus<br><i>(offchain_reporting[at]1.0.0)</i>"]]
10+
Compute -- Value --> data-feeds-report
11+
12+
unnamed3[/"target<br><i>(write_ethereum-testnet-sepolia[at]1.0.0)</i>"\]
13+
data-feeds-report --> unnamed3
14+
15+
```

0 commit comments

Comments
 (0)