From 377e5400e0019434f490f0d22407aa258f568990 Mon Sep 17 00:00:00 2001 From: HenryNguyen5 <6404866+HenryNguyen5@users.noreply.github.com> Date: Tue, 7 May 2024 20:55:51 -0700 Subject: [PATCH 1/3] [Keystone] Merge version field with ID --- go.mod | 1 - pkg/capabilities/capabilities.go | 30 ++++++---- pkg/capabilities/capabilities_test.go | 59 +++++++++++++++---- pkg/capabilities/consensus/ocr3/capability.go | 3 +- .../testdata/fixtures/capability/schema.json | 2 +- .../testdata/fixtures/validator/schema.json | 4 +- pkg/capabilities/triggers/mercury_trigger.go | 3 +- .../triggers/on_demand_trigger.go | 3 +- .../testdata/fixtures/mercury/schema.json | 4 +- .../testdata/fixtures/ondemand/schema.json | 2 +- pkg/capabilities/validate_test.go | 3 +- .../core/services/capability/capabilities.go | 2 - .../capability/capabilities_registry_test.go | 14 ++--- .../services/capability/capabilities_test.go | 4 +- pkg/loop/internal/test/test.go | 3 +- 15 files changed, 86 insertions(+), 51 deletions(-) diff --git a/go.mod b/go.mod index b9ed3661f..c22bf58de 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,6 @@ require ( go.uber.org/zap v1.26.0 golang.org/x/crypto v0.18.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa - golang.org/x/mod v0.14.0 gonum.org/v1/gonum v0.14.0 google.golang.org/grpc v1.58.3 google.golang.org/protobuf v1.31.0 diff --git a/pkg/capabilities/capabilities.go b/pkg/capabilities/capabilities.go index 68780a0ca..ccef1b10c 100644 --- a/pkg/capabilities/capabilities.go +++ b/pkg/capabilities/capabilities.go @@ -5,10 +5,10 @@ import ( "errors" "fmt" "regexp" + "strings" "time" p2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" - "golang.org/x/mod/semver" "github.com/smartcontractkit/chainlink-common/pkg/values" ) @@ -177,16 +177,31 @@ type CapabilityInfo struct { ID string CapabilityType CapabilityType Description string - Version string DON *DON } +// Parse out the version from the ID. +func (c CapabilityInfo) Version() string { + return c.ID[strings.Index(c.ID, "@")+1:] +} + // Info returns the info of the capability. func (c CapabilityInfo) Info(ctx context.Context) (CapabilityInfo, error) { return c, nil } -var idRegex = regexp.MustCompile(`[a-z0-9_\-:]`) +// This regex allows for the following format: +// +// {name}:{label1_key}_{labe1_value}:{label2_key}_{label2_value}@{version} +// +// The version regex is taken from https://semver.org/, but has been modified to support only major versions. +// +// It is also validated when a workflow is being ingested. See the following link for more details: +// https://github.com/smartcontractkit/chainlink/blob/a0d1ce5e9cddc540bba8eb193865646cf0ebc0a8/core/services/workflows/models_yaml.go#L309 +// +// The difference between the regex within the link above and this one is that we do not use double backslashes, since +// we only needed those for JSON schema regex validation. +var idRegex = regexp.MustCompile(`^[a-z0-9_\-:]+@(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`) const ( // TODO: this length was largely picked arbitrarily. @@ -200,7 +215,6 @@ func NewCapabilityInfo( id string, capabilityType CapabilityType, description string, - version string, don *DON, ) (CapabilityInfo, error) { if len(id) > idMaxLength { @@ -210,10 +224,6 @@ func NewCapabilityInfo( return CapabilityInfo{}, fmt.Errorf("invalid id: %s. Allowed: %s", id, idRegex) } - if ok := semver.IsValid(version); !ok { - return CapabilityInfo{}, fmt.Errorf("invalid version: %+v", version) - } - if err := capabilityType.IsValid(); err != nil { return CapabilityInfo{}, err } @@ -222,7 +232,6 @@ func NewCapabilityInfo( ID: id, CapabilityType: capabilityType, Description: description, - Version: version, DON: don, }, nil } @@ -233,10 +242,9 @@ func MustNewCapabilityInfo( id string, capabilityType CapabilityType, description string, - version string, don *DON, ) CapabilityInfo { - c, err := NewCapabilityInfo(id, capabilityType, description, version, don) + c, err := NewCapabilityInfo(id, capabilityType, description, don) if err != nil { panic(err) } diff --git a/pkg/capabilities/capabilities_test.go b/pkg/capabilities/capabilities_test.go index 7f7b8e183..b7827e7a3 100644 --- a/pkg/capabilities/capabilities_test.go +++ b/pkg/capabilities/capabilities_test.go @@ -15,25 +15,52 @@ import ( func Test_CapabilityInfo(t *testing.T) { ci, err := NewCapabilityInfo( - "capability-id", + "capability-id@1", CapabilityTypeAction, "This is a mock capability that doesn't do anything.", - "v1.0.0", nil, ) require.NoError(t, err) gotCi, err := ci.Info(tests.Context(t)) require.NoError(t, err) + require.Equal(t, ci.Version(), "1") + assert.Equal(t, ci, gotCi) + + ci, err = NewCapabilityInfo( + // add build metadata and sha + "capability-id@1+build.1234.sha-5678", + CapabilityTypeAction, + "This is a mock capability that doesn't do anything.", + nil, + ) + require.NoError(t, err) + + gotCi, err = ci.Info(tests.Context(t)) + require.NoError(t, err) + require.Equal(t, ci.Version(), "1+build.1234.sha-5678") + assert.Equal(t, ci, gotCi) + + // prerelease + ci, err = NewCapabilityInfo( + "capability-id@1-beta", + CapabilityTypeAction, + "This is a mock capability that doesn't do anything.", + nil, + ) + require.NoError(t, err) + + gotCi, err = ci.Info(tests.Context(t)) + require.NoError(t, err) + require.Equal(t, ci.Version(), "1-beta") assert.Equal(t, ci, gotCi) } func Test_CapabilityInfo_Invalid(t *testing.T) { _, err := NewCapabilityInfo( - "capability-id", + "capability-id@2", CapabilityType(5), "This is a mock capability that doesn't do anything.", - "v1.0.0", nil, ) assert.ErrorContains(t, err, "invalid capability type") @@ -42,25 +69,38 @@ func Test_CapabilityInfo_Invalid(t *testing.T) { "&!!!", CapabilityTypeAction, "This is a mock capability that doesn't do anything.", - "v1.0.0", nil, ) assert.ErrorContains(t, err, "invalid id") _, err = NewCapabilityInfo( - "mock-capability", + "mock-capability@v1", + CapabilityTypeAction, + "This is a mock capability that doesn't do anything.", + nil, + ) + assert.ErrorContains(t, err, "invalid id") + + _, err = NewCapabilityInfo( + "mock-capability@1.0", + CapabilityTypeAction, + "This is a mock capability that doesn't do anything.", + nil, + ) + assert.ErrorContains(t, err, "invalid id") + + _, err = NewCapabilityInfo( + "mock-capability@1.0.1", CapabilityTypeAction, "This is a mock capability that doesn't do anything.", - "hello", nil, ) - assert.ErrorContains(t, err, "invalid version") + assert.ErrorContains(t, err, "invalid id") _, err = NewCapabilityInfo( strings.Repeat("n", 256), CapabilityTypeAction, "This is a mock capability that doesn't do anything.", - "hello", nil, ) assert.ErrorContains(t, err, "exceeds max length 128") @@ -192,7 +232,6 @@ func Test_MustNewCapabilityInfo(t *testing.T) { "capability-id", CapabilityTypeAction, "This is a mock capability that doesn't do anything.", - "should-panic", nil, ) }) diff --git a/pkg/capabilities/consensus/ocr3/capability.go b/pkg/capabilities/consensus/ocr3/capability.go index b2100e21c..7af72ce79 100644 --- a/pkg/capabilities/consensus/ocr3/capability.go +++ b/pkg/capabilities/consensus/ocr3/capability.go @@ -16,7 +16,7 @@ import ( ) const ( - ocrCapabilityID = "offchain_reporting" + ocrCapabilityID = "offchain_reporting@1" methodStartRequest = "start_request" methodSendResponse = "send_response" @@ -27,7 +27,6 @@ var info = capabilities.MustNewCapabilityInfo( ocrCapabilityID, capabilities.CapabilityTypeConsensus, "OCR3 consensus exposed as a capability.", - "v1.0.0", nil, ) diff --git a/pkg/capabilities/consensus/ocr3/testdata/fixtures/capability/schema.json b/pkg/capabilities/consensus/ocr3/testdata/fixtures/capability/schema.json index e5ef95c5d..5f6a4912b 100644 --- a/pkg/capabilities/consensus/ocr3/testdata/fixtures/capability/schema.json +++ b/pkg/capabilities/consensus/ocr3/testdata/fixtures/capability/schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://github.com/smartcontractkit/chainlink/capabilities/offchain_reporting/root", + "$id": "https://github.com/smartcontractkit/chainlink/capabilities/offchain_reporting@1/root", "properties": { "config": { "properties": { diff --git a/pkg/capabilities/testdata/fixtures/validator/schema.json b/pkg/capabilities/testdata/fixtures/validator/schema.json index 2f7fd6638..90812851d 100644 --- a/pkg/capabilities/testdata/fixtures/validator/schema.json +++ b/pkg/capabilities/testdata/fixtures/validator/schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://github.com/smartcontractkit/chainlink/capabilities/test/root", + "$id": "https://github.com/smartcontractkit/chainlink/capabilities/test@1/root", "properties": { "config": { "properties": { @@ -84,4 +84,4 @@ "outputs" ], "description": "test description" -} \ No newline at end of file +} diff --git a/pkg/capabilities/triggers/mercury_trigger.go b/pkg/capabilities/triggers/mercury_trigger.go index 64164622d..e1e546ca9 100644 --- a/pkg/capabilities/triggers/mercury_trigger.go +++ b/pkg/capabilities/triggers/mercury_trigger.go @@ -14,13 +14,12 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/values" ) -const triggerID = "streams-trigger" +const triggerID = "streams-trigger@1.0.0" var capInfo = capabilities.MustNewCapabilityInfo( triggerID, capabilities.CapabilityTypeTrigger, "Streams Trigger", - "v1.0.0", nil, ) diff --git a/pkg/capabilities/triggers/on_demand_trigger.go b/pkg/capabilities/triggers/on_demand_trigger.go index 819ea4d65..504a2b5fc 100644 --- a/pkg/capabilities/triggers/on_demand_trigger.go +++ b/pkg/capabilities/triggers/on_demand_trigger.go @@ -10,10 +10,9 @@ import ( ) var info = capabilities.MustNewCapabilityInfo( - "on-demand-trigger", + "on-demand-trigger@1", capabilities.CapabilityTypeTrigger, "An example on-demand trigger.", - "v1.0.0", nil, ) diff --git a/pkg/capabilities/triggers/testdata/fixtures/mercury/schema.json b/pkg/capabilities/triggers/testdata/fixtures/mercury/schema.json index 72fca06d2..5690cbf3c 100644 --- a/pkg/capabilities/triggers/testdata/fixtures/mercury/schema.json +++ b/pkg/capabilities/triggers/testdata/fixtures/mercury/schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://github.com/smartcontractkit/chainlink/capabilities/streams-trigger/root", + "$id": "https://github.com/smartcontractkit/chainlink/capabilities/streams-trigger@1/root", "properties": { "config": { "properties": { @@ -69,4 +69,4 @@ "outputs" ], "description": "Streams Trigger" -} \ No newline at end of file +} diff --git a/pkg/capabilities/triggers/testdata/fixtures/ondemand/schema.json b/pkg/capabilities/triggers/testdata/fixtures/ondemand/schema.json index 647ade228..e1d944775 100644 --- a/pkg/capabilities/triggers/testdata/fixtures/ondemand/schema.json +++ b/pkg/capabilities/triggers/testdata/fixtures/ondemand/schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://github.com/smartcontractkit/chainlink/capabilities/on-demand-trigger/root", + "$id": "https://github.com/smartcontractkit/chainlink/capabilities/on-demand-trigger@1/root", "properties": { "config": { "properties": {}, diff --git a/pkg/capabilities/validate_test.go b/pkg/capabilities/validate_test.go index 44907ff93..160a75b73 100644 --- a/pkg/capabilities/validate_test.go +++ b/pkg/capabilities/validate_test.go @@ -200,10 +200,9 @@ func TestValidator_ValidateOutputs(t *testing.T) { func TestValidator_GenerateSchema(t *testing.T) { capInfo := CapabilityInfo{ - ID: "test", + ID: "test@1", CapabilityType: CapabilityTypeTrigger, Description: "test description", - Version: "1.0.0", } v := NewValidator[TestConfig, TestInputs, TestOutputs](ValidatorArgs{Info: capInfo}) schema, err := v.Schema() diff --git a/pkg/loop/internal/core/services/capability/capabilities.go b/pkg/loop/internal/core/services/capability/capabilities.go index 4c111446a..22536535c 100644 --- a/pkg/loop/internal/core/services/capability/capabilities.go +++ b/pkg/loop/internal/core/services/capability/capabilities.go @@ -134,7 +134,6 @@ func (c *baseCapabilityServer) Info(ctx context.Context, request *emptypb.Empty) Id: info.ID, CapabilityType: ct, Description: info.Description, - Version: info.Version, }, nil } @@ -173,7 +172,6 @@ func (c *baseCapabilityClient) Info(ctx context.Context) (capabilities.Capabilit ID: resp.Id, CapabilityType: ct, Description: resp.Description, - Version: resp.Version, }, nil } diff --git a/pkg/loop/internal/core/services/capability/capabilities_registry_test.go b/pkg/loop/internal/core/services/capability/capabilities_registry_test.go index e384f75f5..1fcc98181 100644 --- a/pkg/loop/internal/core/services/capability/capabilities_registry_test.go +++ b/pkg/loop/internal/core/services/capability/capabilities_registry_test.go @@ -176,10 +176,9 @@ func TestCapabilitiesRegistry(t *testing.T) { // Add capability Trigger triggerInfo := capabilities.CapabilityInfo{ - ID: "trigger-1", + ID: "trigger-1@1", CapabilityType: capabilities.CapabilityTypeTrigger, Description: "trigger-1-description", - Version: "trigger-1-version", } testTrigger := mockTriggerCapability{ mockBaseCapability: &mockBaseCapability{info: triggerInfo}, @@ -217,10 +216,9 @@ func TestCapabilitiesRegistry(t *testing.T) { // Add capability Trigger actionInfo := capabilities.CapabilityInfo{ - ID: "action-1", + ID: "action-1@2", CapabilityType: capabilities.CapabilityTypeAction, Description: "action-1-description", - Version: "action-1-version", } actionCallbackChan := make(chan capabilities.CapabilityResponse, 10) @@ -254,10 +252,9 @@ func TestCapabilitiesRegistry(t *testing.T) { // Add capability Consensus consensusInfo := capabilities.CapabilityInfo{ - ID: "consensus-1", + ID: "consensus-1@3", CapabilityType: capabilities.CapabilityTypeConsensus, Description: "consensus-1-description", - Version: "consensus-1-version", } testConsensus := mockConsensusCapability{ mockBaseCapability: &mockBaseCapability{info: consensusInfo}, @@ -271,10 +268,9 @@ func TestCapabilitiesRegistry(t *testing.T) { // Add capability Target targetInfo := capabilities.CapabilityInfo{ - ID: "target-1", + ID: "target-1@1", CapabilityType: capabilities.CapabilityTypeTarget, Description: "target-1-description", - Version: "target-1-version", } testTarget := mockTargetCapability{ mockBaseCapability: &mockBaseCapability{info: targetInfo}, @@ -293,5 +289,5 @@ func testCapabilityInfo(t *testing.T, expectedInfo capabilities.CapabilityInfo, require.Equal(t, expectedInfo.ID, gotInfo.ID) require.Equal(t, expectedInfo.CapabilityType, gotInfo.CapabilityType) require.Equal(t, expectedInfo.Description, gotInfo.Description) - require.Equal(t, expectedInfo.Version, gotInfo.Version) + require.Equal(t, expectedInfo.Version(), gotInfo.Version()) } diff --git a/pkg/loop/internal/core/services/capability/capabilities_test.go b/pkg/loop/internal/core/services/capability/capabilities_test.go index b34188529..1d0010def 100644 --- a/pkg/loop/internal/core/services/capability/capabilities_test.go +++ b/pkg/loop/internal/core/services/capability/capabilities_test.go @@ -69,7 +69,7 @@ func (m *mockTrigger) Stop() { func mustMockTrigger(t *testing.T) *mockTrigger { return &mockTrigger{ - BaseCapability: capabilities.MustNewCapabilityInfo("trigger", capabilities.CapabilityTypeTrigger, "a mock trigger", "v0.0.1", nil), + BaseCapability: capabilities.MustNewCapabilityInfo("trigger@1", capabilities.CapabilityTypeTrigger, "a mock trigger", nil), callback: make(chan capabilities.CapabilityResponse, 10), unregisterCalls: make(chan bool, 10), registerCalls: make(chan bool, 10), @@ -99,7 +99,7 @@ func (m *mockCallback) Execute(ctx context.Context, request capabilities.Capabil func mustMockCallback(t *testing.T, _type capabilities.CapabilityType) *mockCallback { return &mockCallback{ - BaseCapability: capabilities.MustNewCapabilityInfo(fmt.Sprintf("callback %s", _type), _type, fmt.Sprintf("a mock %s", _type), "v0.0.1", nil), + BaseCapability: capabilities.MustNewCapabilityInfo(fmt.Sprintf("callback-%s@1", _type), _type, fmt.Sprintf("a mock %s", _type), nil), callback: make(chan capabilities.CapabilityResponse), } } diff --git a/pkg/loop/internal/test/test.go b/pkg/loop/internal/test/test.go index a5d0a9347..7d4a305a7 100644 --- a/pkg/loop/internal/test/test.go +++ b/pkg/loop/internal/test/test.go @@ -19,10 +19,9 @@ var ( GetConsensusID = "get-consensus-id" GetTargetID = "get-target-id" CapabilityInfo = capabilities.CapabilityInfo{ - ID: "capability-info-id", + ID: "capability-info-id@1", CapabilityType: 2, Description: "capability-info-description", - Version: "capability-info-version", } ) From ec140ee8903257083bcf8498528a23c82afb7208 Mon Sep 17 00:00:00 2001 From: HenryNguyen5 <6404866+HenryNguyen5@users.noreply.github.com> Date: Thu, 23 May 2024 21:59:18 -0400 Subject: [PATCH 2/3] Use full versioning for capabilities --- pkg/capabilities/capabilities.go | 2 +- pkg/capabilities/capabilities_test.go | 18 +++++++------- pkg/capabilities/consensus/ocr3/capability.go | 2 +- .../testdata/fixtures/capability/schema.json | 4 ++-- .../testdata/fixtures/validator/schema.json | 2 +- .../triggers/on_demand_trigger.go | 2 +- .../testdata/fixtures/mercury/schema.json | 2 +- .../testdata/fixtures/ondemand/schema.json | 4 ++-- pkg/capabilities/validate_test.go | 2 +- .../capability/capabilities_registry_test.go | 24 +++++++++---------- .../services/capability/capabilities_test.go | 4 ++-- pkg/loop/internal/test/test.go | 2 +- 12 files changed, 34 insertions(+), 34 deletions(-) diff --git a/pkg/capabilities/capabilities.go b/pkg/capabilities/capabilities.go index ccef1b10c..56e2a4438 100644 --- a/pkg/capabilities/capabilities.go +++ b/pkg/capabilities/capabilities.go @@ -201,7 +201,7 @@ func (c CapabilityInfo) Info(ctx context.Context) (CapabilityInfo, error) { // // The difference between the regex within the link above and this one is that we do not use double backslashes, since // we only needed those for JSON schema regex validation. -var idRegex = regexp.MustCompile(`^[a-z0-9_\-:]+@(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`) +var idRegex = regexp.MustCompile(`^[a-z0-9_\-:]+@(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`) const ( // TODO: this length was largely picked arbitrarily. diff --git a/pkg/capabilities/capabilities_test.go b/pkg/capabilities/capabilities_test.go index b7827e7a3..871006c8e 100644 --- a/pkg/capabilities/capabilities_test.go +++ b/pkg/capabilities/capabilities_test.go @@ -15,7 +15,7 @@ import ( func Test_CapabilityInfo(t *testing.T) { ci, err := NewCapabilityInfo( - "capability-id@1", + "capability-id@1.0.0", CapabilityTypeAction, "This is a mock capability that doesn't do anything.", nil, @@ -24,12 +24,12 @@ func Test_CapabilityInfo(t *testing.T) { gotCi, err := ci.Info(tests.Context(t)) require.NoError(t, err) - require.Equal(t, ci.Version(), "1") + require.Equal(t, ci.Version(), "1.0.0") assert.Equal(t, ci, gotCi) ci, err = NewCapabilityInfo( // add build metadata and sha - "capability-id@1+build.1234.sha-5678", + "capability-id@1.0.0+build.1234.sha-5678", CapabilityTypeAction, "This is a mock capability that doesn't do anything.", nil, @@ -38,12 +38,12 @@ func Test_CapabilityInfo(t *testing.T) { gotCi, err = ci.Info(tests.Context(t)) require.NoError(t, err) - require.Equal(t, ci.Version(), "1+build.1234.sha-5678") + require.Equal(t, ci.Version(), "1.0.0+build.1234.sha-5678") assert.Equal(t, ci, gotCi) // prerelease ci, err = NewCapabilityInfo( - "capability-id@1-beta", + "capability-id@1.0.0-beta", CapabilityTypeAction, "This is a mock capability that doesn't do anything.", nil, @@ -52,13 +52,13 @@ func Test_CapabilityInfo(t *testing.T) { gotCi, err = ci.Info(tests.Context(t)) require.NoError(t, err) - require.Equal(t, ci.Version(), "1-beta") + require.Equal(t, ci.Version(), "1.0.0-beta") assert.Equal(t, ci, gotCi) } func Test_CapabilityInfo_Invalid(t *testing.T) { _, err := NewCapabilityInfo( - "capability-id@2", + "capability-id@2.0.0", CapabilityType(5), "This is a mock capability that doesn't do anything.", nil, @@ -74,7 +74,7 @@ func Test_CapabilityInfo_Invalid(t *testing.T) { assert.ErrorContains(t, err, "invalid id") _, err = NewCapabilityInfo( - "mock-capability@v1", + "mock-capability@v1.0.0", CapabilityTypeAction, "This is a mock capability that doesn't do anything.", nil, @@ -90,7 +90,7 @@ func Test_CapabilityInfo_Invalid(t *testing.T) { assert.ErrorContains(t, err, "invalid id") _, err = NewCapabilityInfo( - "mock-capability@1.0.1", + "mock-capability@1", CapabilityTypeAction, "This is a mock capability that doesn't do anything.", nil, diff --git a/pkg/capabilities/consensus/ocr3/capability.go b/pkg/capabilities/consensus/ocr3/capability.go index 7af72ce79..c53158083 100644 --- a/pkg/capabilities/consensus/ocr3/capability.go +++ b/pkg/capabilities/consensus/ocr3/capability.go @@ -16,7 +16,7 @@ import ( ) const ( - ocrCapabilityID = "offchain_reporting@1" + ocrCapabilityID = "offchain_reporting@1.0.0" methodStartRequest = "start_request" methodSendResponse = "send_response" diff --git a/pkg/capabilities/consensus/ocr3/testdata/fixtures/capability/schema.json b/pkg/capabilities/consensus/ocr3/testdata/fixtures/capability/schema.json index 5f6a4912b..c1d6f1276 100644 --- a/pkg/capabilities/consensus/ocr3/testdata/fixtures/capability/schema.json +++ b/pkg/capabilities/consensus/ocr3/testdata/fixtures/capability/schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://github.com/smartcontractkit/chainlink/capabilities/offchain_reporting@1/root", + "$id": "https://github.com/smartcontractkit/chainlink/capabilities/offchain_reporting@1.0.0/root", "properties": { "config": { "properties": { @@ -94,4 +94,4 @@ "outputs" ], "description": "OCR3 consensus exposed as a capability." -} \ No newline at end of file +} diff --git a/pkg/capabilities/testdata/fixtures/validator/schema.json b/pkg/capabilities/testdata/fixtures/validator/schema.json index 90812851d..70f84cf15 100644 --- a/pkg/capabilities/testdata/fixtures/validator/schema.json +++ b/pkg/capabilities/testdata/fixtures/validator/schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://github.com/smartcontractkit/chainlink/capabilities/test@1/root", + "$id": "https://github.com/smartcontractkit/chainlink/capabilities/test@1.0.0/root", "properties": { "config": { "properties": { diff --git a/pkg/capabilities/triggers/on_demand_trigger.go b/pkg/capabilities/triggers/on_demand_trigger.go index 504a2b5fc..7fd213ca9 100644 --- a/pkg/capabilities/triggers/on_demand_trigger.go +++ b/pkg/capabilities/triggers/on_demand_trigger.go @@ -10,7 +10,7 @@ import ( ) var info = capabilities.MustNewCapabilityInfo( - "on-demand-trigger@1", + "on-demand-trigger@1.0.0", capabilities.CapabilityTypeTrigger, "An example on-demand trigger.", nil, diff --git a/pkg/capabilities/triggers/testdata/fixtures/mercury/schema.json b/pkg/capabilities/triggers/testdata/fixtures/mercury/schema.json index 5690cbf3c..ce00c11ae 100644 --- a/pkg/capabilities/triggers/testdata/fixtures/mercury/schema.json +++ b/pkg/capabilities/triggers/testdata/fixtures/mercury/schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://github.com/smartcontractkit/chainlink/capabilities/streams-trigger@1/root", + "$id": "https://github.com/smartcontractkit/chainlink/capabilities/streams-trigger@1.0.0/root", "properties": { "config": { "properties": { diff --git a/pkg/capabilities/triggers/testdata/fixtures/ondemand/schema.json b/pkg/capabilities/triggers/testdata/fixtures/ondemand/schema.json index e1d944775..18cdcc815 100644 --- a/pkg/capabilities/triggers/testdata/fixtures/ondemand/schema.json +++ b/pkg/capabilities/triggers/testdata/fixtures/ondemand/schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://github.com/smartcontractkit/chainlink/capabilities/on-demand-trigger@1/root", + "$id": "https://github.com/smartcontractkit/chainlink/capabilities/on-demand-trigger@1.0.0/root", "properties": { "config": { "properties": {}, @@ -27,4 +27,4 @@ "outputs" ], "description": "An example on-demand trigger." -} \ No newline at end of file +} diff --git a/pkg/capabilities/validate_test.go b/pkg/capabilities/validate_test.go index 160a75b73..125cdac0e 100644 --- a/pkg/capabilities/validate_test.go +++ b/pkg/capabilities/validate_test.go @@ -200,7 +200,7 @@ func TestValidator_ValidateOutputs(t *testing.T) { func TestValidator_GenerateSchema(t *testing.T) { capInfo := CapabilityInfo{ - ID: "test@1", + ID: "test@1.0.0", CapabilityType: CapabilityTypeTrigger, Description: "test description", } diff --git a/pkg/loop/internal/core/services/capability/capabilities_registry_test.go b/pkg/loop/internal/core/services/capability/capabilities_registry_test.go index 1fcc98181..b3ed31fe5 100644 --- a/pkg/loop/internal/core/services/capability/capabilities_registry_test.go +++ b/pkg/loop/internal/core/services/capability/capabilities_registry_test.go @@ -176,7 +176,7 @@ func TestCapabilitiesRegistry(t *testing.T) { // Add capability Trigger triggerInfo := capabilities.CapabilityInfo{ - ID: "trigger-1@1", + ID: "trigger-1@1.0.0", CapabilityType: capabilities.CapabilityTypeTrigger, Description: "trigger-1-description", } @@ -190,8 +190,8 @@ func TestCapabilitiesRegistry(t *testing.T) { err = rc.Add(tests.Context(t), testTrigger) require.NoError(t, err) - reg.On("GetTrigger", mock.Anything, "trigger-1").Return(testTrigger, nil) - triggerCap, err := rc.GetTrigger(tests.Context(t), "trigger-1") + reg.On("GetTrigger", mock.Anything, "trigger-1@1.0.0").Return(testTrigger, nil) + triggerCap, err := rc.GetTrigger(tests.Context(t), "trigger-1@1.0.0") require.NoError(t, err) // Test trigger Info() @@ -216,7 +216,7 @@ func TestCapabilitiesRegistry(t *testing.T) { // Add capability Trigger actionInfo := capabilities.CapabilityInfo{ - ID: "action-1@2", + ID: "action-1@2.0.0", CapabilityType: capabilities.CapabilityTypeAction, Description: "action-1-description", } @@ -226,8 +226,8 @@ func TestCapabilitiesRegistry(t *testing.T) { mockBaseCapability: &mockBaseCapability{info: actionInfo}, mockCallbackExecutable: &mockCallbackExecutable{callback: actionCallbackChan}, } - reg.On("GetAction", mock.Anything, "action-1").Return(testAction, nil) - actionCap, err := rc.GetAction(tests.Context(t), "action-1") + reg.On("GetAction", mock.Anything, "action-1@2.0.0").Return(testAction, nil) + actionCap, err := rc.GetAction(tests.Context(t), "action-1@2.0.0") require.NoError(t, err) testCapabilityInfo(t, actionInfo, actionCap) @@ -252,7 +252,7 @@ func TestCapabilitiesRegistry(t *testing.T) { // Add capability Consensus consensusInfo := capabilities.CapabilityInfo{ - ID: "consensus-1@3", + ID: "consensus-1@3.0.0", CapabilityType: capabilities.CapabilityTypeConsensus, Description: "consensus-1-description", } @@ -260,15 +260,15 @@ func TestCapabilitiesRegistry(t *testing.T) { mockBaseCapability: &mockBaseCapability{info: consensusInfo}, mockCallbackExecutable: &mockCallbackExecutable{}, } - reg.On("GetConsensus", mock.Anything, "consensus-1").Return(testConsensus, nil) - consensusCap, err := rc.GetConsensus(tests.Context(t), "consensus-1") + reg.On("GetConsensus", mock.Anything, "consensus-1@3.0.0").Return(testConsensus, nil) + consensusCap, err := rc.GetConsensus(tests.Context(t), "consensus-1@3.0.0") require.NoError(t, err) testCapabilityInfo(t, consensusInfo, consensusCap) // Add capability Target targetInfo := capabilities.CapabilityInfo{ - ID: "target-1@1", + ID: "target-1@1.0.0", CapabilityType: capabilities.CapabilityTypeTarget, Description: "target-1-description", } @@ -276,8 +276,8 @@ func TestCapabilitiesRegistry(t *testing.T) { mockBaseCapability: &mockBaseCapability{info: targetInfo}, mockCallbackExecutable: &mockCallbackExecutable{}, } - reg.On("GetTarget", mock.Anything, "target-1").Return(testTarget, nil) - targetCap, err := rc.GetTarget(tests.Context(t), "target-1") + reg.On("GetTarget", mock.Anything, "target-1@1.0.0").Return(testTarget, nil) + targetCap, err := rc.GetTarget(tests.Context(t), "target-1@1.0.0") require.NoError(t, err) testCapabilityInfo(t, targetInfo, targetCap) diff --git a/pkg/loop/internal/core/services/capability/capabilities_test.go b/pkg/loop/internal/core/services/capability/capabilities_test.go index 1d0010def..580c1dc09 100644 --- a/pkg/loop/internal/core/services/capability/capabilities_test.go +++ b/pkg/loop/internal/core/services/capability/capabilities_test.go @@ -69,7 +69,7 @@ func (m *mockTrigger) Stop() { func mustMockTrigger(t *testing.T) *mockTrigger { return &mockTrigger{ - BaseCapability: capabilities.MustNewCapabilityInfo("trigger@1", capabilities.CapabilityTypeTrigger, "a mock trigger", nil), + BaseCapability: capabilities.MustNewCapabilityInfo("trigger@1.0.0", capabilities.CapabilityTypeTrigger, "a mock trigger", nil), callback: make(chan capabilities.CapabilityResponse, 10), unregisterCalls: make(chan bool, 10), registerCalls: make(chan bool, 10), @@ -99,7 +99,7 @@ func (m *mockCallback) Execute(ctx context.Context, request capabilities.Capabil func mustMockCallback(t *testing.T, _type capabilities.CapabilityType) *mockCallback { return &mockCallback{ - BaseCapability: capabilities.MustNewCapabilityInfo(fmt.Sprintf("callback-%s@1", _type), _type, fmt.Sprintf("a mock %s", _type), nil), + BaseCapability: capabilities.MustNewCapabilityInfo(fmt.Sprintf("callback-%s@1.0.0", _type), _type, fmt.Sprintf("a mock %s", _type), nil), callback: make(chan capabilities.CapabilityResponse), } } diff --git a/pkg/loop/internal/test/test.go b/pkg/loop/internal/test/test.go index 7d4a305a7..14ae0ddab 100644 --- a/pkg/loop/internal/test/test.go +++ b/pkg/loop/internal/test/test.go @@ -19,7 +19,7 @@ var ( GetConsensusID = "get-consensus-id" GetTargetID = "get-target-id" CapabilityInfo = capabilities.CapabilityInfo{ - ID: "capability-info-id@1", + ID: "capability-info-id@1.0.0", CapabilityType: 2, Description: "capability-info-description", } From 54707d3e6c8e99cf817a37e1b2f84fe016b3c264 Mon Sep 17 00:00:00 2001 From: HenryNguyen5 <6404866+HenryNguyen5@users.noreply.github.com> Date: Thu, 23 May 2024 22:19:14 -0400 Subject: [PATCH 3/3] Use full capability versioning in workflow yaml --- pkg/workflows/models_yaml.go | 8 ++++---- pkg/workflows/models_yaml_test.go | 4 ++-- .../fixtures/workflows/marshalling/workflow_1.yaml | 6 +++--- .../fixtures/workflows/marshalling/workflow_2.yaml | 4 ++-- .../fixtures/workflows/marshalling/workflow_2_spec.json | 4 ++-- .../testdata/fixtures/workflows/references/failing_1.yaml | 6 +++--- .../testdata/fixtures/workflows/references/passing_1.yaml | 6 +++--- .../testdata/fixtures/workflows/versioning/failing_1.yaml | 3 +-- .../testdata/fixtures/workflows/versioning/failing_2.yaml | 7 +++---- .../testdata/fixtures/workflows/versioning/passing_1.yaml | 6 +++--- .../testdata/fixtures/workflows/workflow_schema.json | 4 ++-- 11 files changed, 28 insertions(+), 30 deletions(-) diff --git a/pkg/workflows/models_yaml.go b/pkg/workflows/models_yaml.go index 877d8835c..b8f76ca1b 100644 --- a/pkg/workflows/models_yaml.go +++ b/pkg/workflows/models_yaml.go @@ -186,7 +186,7 @@ type stepDefinitionYaml struct { // (For Keystone only.) More specific than a major version is specified. // // Example (string) - // id: read_chain:chain_ethereum:network_mainnet@1 + // id: read_chain:chain_ethereum:network_mainnet@1.0.0 // // Example (table) // @@ -233,7 +233,7 @@ type stepDefinitionYaml struct { // // Example // targets: - // - id: write_polygon_mainnet@1 + // - id: write_polygon_mainnet@1.0.0 // inputs: // report: // - consensus.evm_median.outputs.report @@ -305,7 +305,7 @@ func (stepDefinitionID) JSONSchema() *jsonschema.Schema { tableSchema := reflector.Reflect(&stepDefinitionTableID{}) stringSchema := &jsonschema.Schema{ ID: "string", - Pattern: "^[a-z0-9_\\-:]+@(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", + Pattern: "^[a-z0-9_\\-:]+@(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", } return &jsonschema.Schema{ @@ -320,7 +320,7 @@ func (stepDefinitionID) JSONSchema() *jsonschema.Schema { // stepDefinitionTableID is the structured representation of a stepDefinitionID. type stepDefinitionTableID struct { Name string `json:"name"` - Version string `json:"version" jsonschema:"pattern=(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"` + Version string `json:"version" jsonschema:"pattern=(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"` Labels map[string]string `json:"labels"` } diff --git a/pkg/workflows/models_yaml_test.go b/pkg/workflows/models_yaml_test.go index e7e638070..6abfe5930 100644 --- a/pkg/workflows/models_yaml_test.go +++ b/pkg/workflows/models_yaml_test.go @@ -152,7 +152,7 @@ func TestWorkflowSpecMarshalling(t *testing.T) { require.NoError(t, err) // change this to update golden file - shouldUpdateWorkflowSpec := false + shouldUpdateWorkflowSpec := true if shouldUpdateWorkflowSpec { err = os.WriteFile(expectedSpecPath, workflowSpecBytes, 0600) require.NoError(t, err) @@ -176,7 +176,7 @@ func TestJsonSchema(t *testing.T) { require.NoError(t, err) // change this to update golden file - shouldUpdateSchema := false + shouldUpdateSchema := true if shouldUpdateSchema { err = os.WriteFile(expectedSchemaPath, generatedSchema, 0600) require.NoError(t, err) diff --git a/pkg/workflows/testdata/fixtures/workflows/marshalling/workflow_1.yaml b/pkg/workflows/testdata/fixtures/workflows/marshalling/workflow_1.yaml index 9a9870af8..b2be6f5c8 100644 --- a/pkg/workflows/testdata/fixtures/workflows/marshalling/workflow_1.yaml +++ b/pkg/workflows/testdata/fixtures/workflows/marshalling/workflow_1.yaml @@ -1,5 +1,5 @@ triggers: - - id: mercury-trigger@1 + - id: mercury-trigger@1.0.0 ref: report_data config: boolean_coercion: @@ -54,7 +54,7 @@ # no actions consensus: - - id: offchain_reporting@1 + - id: offchain_reporting@1.0.0 inputs: observations: - triggers.report_data.outputs @@ -76,7 +76,7 @@ abi: "mercury_reports bytes[]" targets: - - id: write_polygon_mainnet@1 + - id: write_polygon_mainnet@1.0.0 inputs: report: - consensus.evm_median.outputs.report diff --git a/pkg/workflows/testdata/fixtures/workflows/marshalling/workflow_2.yaml b/pkg/workflows/testdata/fixtures/workflows/marshalling/workflow_2.yaml index be40a91da..c875b995f 100644 --- a/pkg/workflows/testdata/fixtures/workflows/marshalling/workflow_2.yaml +++ b/pkg/workflows/testdata/fixtures/workflows/marshalling/workflow_2.yaml @@ -1,5 +1,5 @@ triggers: - - id: on_mercury_report@1 + - id: on_mercury_report@1.0.0 ref: report_data config: {} @@ -19,7 +19,7 @@ - triggers.report_data.outputs targets: - - id: write_polygon_mainnet@1 + - id: write_polygon_mainnet@1.0.0 config: {} inputs: report: diff --git a/pkg/workflows/testdata/fixtures/workflows/marshalling/workflow_2_spec.json b/pkg/workflows/testdata/fixtures/workflows/marshalling/workflow_2_spec.json index 000fa4692..7c77b6c00 100644 --- a/pkg/workflows/testdata/fixtures/workflows/marshalling/workflow_2_spec.json +++ b/pkg/workflows/testdata/fixtures/workflows/marshalling/workflow_2_spec.json @@ -1,7 +1,7 @@ { "triggers": [ { - "id": "on_mercury_report@1", + "id": "on_mercury_report@1.0.0", "ref": "report_data", "config": {} } @@ -19,7 +19,7 @@ ], "targets": [ { - "id": "write_polygon_mainnet@1", + "id": "write_polygon_mainnet@1.0.0", "inputs": { "report": [ "consensus.evm_median.outputs.report" diff --git a/pkg/workflows/testdata/fixtures/workflows/references/failing_1.yaml b/pkg/workflows/testdata/fixtures/workflows/references/failing_1.yaml index b3c984e98..9b2d45516 100644 --- a/pkg/workflows/testdata/fixtures/workflows/references/failing_1.yaml +++ b/pkg/workflows/testdata/fixtures/workflows/references/failing_1.yaml @@ -1,14 +1,14 @@ triggers: -- id: trigger_test@1 +- id: trigger_test@1.0.0 config: {} consensus: - - id: offchain_reporting@1 + - id: offchain_reporting@1.0.0 ref: offchain_reporting=1 config: {} targets: - - id: write_polygon_mainnet@1 + - id: write_polygon_mainnet@1.0.0 ref: write_polygon_mainnet_1 config: {} diff --git a/pkg/workflows/testdata/fixtures/workflows/references/passing_1.yaml b/pkg/workflows/testdata/fixtures/workflows/references/passing_1.yaml index cb2f424e9..1daea851d 100644 --- a/pkg/workflows/testdata/fixtures/workflows/references/passing_1.yaml +++ b/pkg/workflows/testdata/fixtures/workflows/references/passing_1.yaml @@ -1,14 +1,14 @@ triggers: -- id: trigger_test@1 +- id: trigger_test@1.0.0 config: {} consensus: - - id: offchain_reporting@1 + - id: offchain_reporting@1.0.0 ref: offchain_reporting_1 config: {} targets: - - id: write_polygon_mainnet@1 + - id: write_polygon_mainnet@1.0.0 ref: write_polygon_mainnet_1 config: {} diff --git a/pkg/workflows/testdata/fixtures/workflows/versioning/failing_1.yaml b/pkg/workflows/testdata/fixtures/workflows/versioning/failing_1.yaml index 2e41eeb98..85ec011d5 100644 --- a/pkg/workflows/testdata/fixtures/workflows/versioning/failing_1.yaml +++ b/pkg/workflows/testdata/fixtures/workflows/versioning/failing_1.yaml @@ -1,4 +1,3 @@ -# Should fail since version is more specific than major triggers: - id: trigger_test@1.0 config: {} @@ -9,7 +8,7 @@ consensus: config: {} targets: - - id: write_polygon_mainnet@1 + - id: write_polygon_mainnet@1.0.0 ref: write_polygon_mainnet_1 config: {} diff --git a/pkg/workflows/testdata/fixtures/workflows/versioning/failing_2.yaml b/pkg/workflows/testdata/fixtures/workflows/versioning/failing_2.yaml index 36cd5b68b..a947de76e 100644 --- a/pkg/workflows/testdata/fixtures/workflows/versioning/failing_2.yaml +++ b/pkg/workflows/testdata/fixtures/workflows/versioning/failing_2.yaml @@ -1,16 +1,15 @@ -# Should fail since version is more specific than major triggers: - - id: trigger_test@1.0.0 + - id: trigger_test@1 config: {} consensus: - - id: offchain_reporting@1 + - id: offchain_reporting@1.0 ref: offchain_reporting_1 config: {} targets: - - id: write_polygon_mainnet@1 + - id: write_polygon_mainnet@1.0.0 ref: write_polygon_mainnet_1 config: {} diff --git a/pkg/workflows/testdata/fixtures/workflows/versioning/passing_1.yaml b/pkg/workflows/testdata/fixtures/workflows/versioning/passing_1.yaml index 4579c2899..261c90995 100644 --- a/pkg/workflows/testdata/fixtures/workflows/versioning/passing_1.yaml +++ b/pkg/workflows/testdata/fixtures/workflows/versioning/passing_1.yaml @@ -1,14 +1,14 @@ triggers: - - id: trigger_test@1 + - id: trigger_test@1.0.0 config: {} consensus: - - id: offchain_reporting@1-beta.1 + - id: offchain_reporting@1.0.0-beta.1 ref: offchain_reporting_1 config: {} targets: - - id: write_polygon_mainnet@1-alpha+sha246er3 + - id: write_polygon_mainnet@1.0.0-alpha+sha246er3 ref: write_polygon_mainnet_1 config: {} diff --git a/pkg/workflows/testdata/fixtures/workflows/workflow_schema.json b/pkg/workflows/testdata/fixtures/workflows/workflow_schema.json index 1c7fbc850..46beda0c2 100644 --- a/pkg/workflows/testdata/fixtures/workflows/workflow_schema.json +++ b/pkg/workflows/testdata/fixtures/workflows/workflow_schema.json @@ -10,7 +10,7 @@ "oneOf": [ { "$id": "string", - "pattern": "^[a-z0-9_\\-:]+@(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" + "pattern": "^[a-z0-9_\\-:]+@(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" }, { "$schema": "https://json-schema.org/draft/2020-12/schema", @@ -21,7 +21,7 @@ }, "version": { "type": "string", - "pattern": "(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" + "pattern": "(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" }, "labels": { "additionalProperties": {