polyn-cli 0.1.9 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +4 -4
- data/lib/polyn/cli/consumer_generator.rb +17 -17
- data/lib/polyn/cli/naming.rb +13 -13
- data/lib/polyn/cli/schema_generator.rb +10 -10
- data/lib/polyn/cli/schema_loader.rb +46 -57
- data/lib/polyn/cli/version.rb +1 -1
- data/lib/polyn/cli.rb +10 -11
- data/lib/polyn/templates/Dockerfile +2 -2
- data/lib/polyn/templates/README.md +17 -22
- data/lib/polyn/templates/generators/schema.json +1 -1
- data/lib/polyn/templates/schemas/money.amount.v1.json +15 -0
- data/lib/polyn/templates/{events → schemas}/widgets.created.v1.json +0 -0
- metadata +4 -6
- data/lib/polyn/cli/cloud_event.rb +0 -15
- data/lib/polyn/cloud-event-schema.json +0 -187
- data/lib/polyn/templates/events/.gitkeep +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 918d9c6f737ba311705c8190127536babc3e87260eceecdcacef5f40111945a7
|
4
|
+
data.tar.gz: d1048eaa24a80e2db328b511d014fd3232cad90bea8071f899ddead93bb2327f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: becfe06189a3250f4db8b89e1bfdcb0a89d0973c49ef5fd308105862b44a5ebb284ff4d7c55cca6e11cf528b5cd6b505867bc0912475bf3d32b825a0ab6fad1a
|
7
|
+
data.tar.gz: '0793abb236bc93a4c0d3affb83c96548ca380f67adef929ac011e49b53b9d4e1678e1b9777b9307e5131c2d2c7f266af7397af72be8c25ea6e2f015f2c1585f5'
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -10,9 +10,9 @@ gem install 'polyn-cli'
|
|
10
10
|
|
11
11
|
## Usage
|
12
12
|
|
13
|
-
### Create New
|
13
|
+
### Create New Schemas Codebase
|
14
14
|
|
15
|
-
Run `polyn init` inside a directory to create a new `
|
15
|
+
Run `polyn init` inside a directory to create a new `schemas` respository for managing your message schemas and NATS server configuration
|
16
16
|
|
17
17
|
### Stream Generator
|
18
18
|
|
@@ -20,11 +20,11 @@ Run `polyn gen:stream <stream_name>` to generate a new configuration file for a
|
|
20
20
|
|
21
21
|
### Schema Generator
|
22
22
|
|
23
|
-
Run `polyn gen:schema <
|
23
|
+
Run `polyn gen:schema <schema_name>` to generate a new JSON Schema for a message
|
24
24
|
|
25
25
|
### Consumer Generator
|
26
26
|
|
27
|
-
Run `polyn gen:consumer <stream_name> <destination_name> <
|
27
|
+
Run `polyn gen:consumer <stream_name> <destination_name> <schema_name>` to generate new configuration for a consumer of a stream. It will be included in the same file as the stream configuration.
|
28
28
|
|
29
29
|
### Updating NATS Configuration and Schemas
|
30
30
|
|
@@ -9,10 +9,10 @@ module Polyn
|
|
9
9
|
|
10
10
|
desc "Generates a new NATS Consumer configuration for a stream"
|
11
11
|
|
12
|
-
argument :stream_name, required: true, desc: "The name of the stream to consume
|
12
|
+
argument :stream_name, required: true, desc: "The name of the stream to consume messages from"
|
13
13
|
argument :destination_name, required: true,
|
14
|
-
desc: "The name of the application, service, or component consuming the
|
15
|
-
argument :
|
14
|
+
desc: "The name of the application, service, or component consuming the message"
|
15
|
+
argument :message_name, required: true, desc: "The name of the message being consumed"
|
16
16
|
class_option :dir, default: Dir.getwd
|
17
17
|
|
18
18
|
source_root File.join(File.expand_path(__dir__), "../templates")
|
@@ -20,22 +20,22 @@ module Polyn
|
|
20
20
|
def check_names
|
21
21
|
Polyn::Cli::Naming.validate_stream_name!(stream_name)
|
22
22
|
Polyn::Cli::Naming.validate_destination_name!(destination_name)
|
23
|
-
Polyn::Cli::Naming.
|
23
|
+
Polyn::Cli::Naming.validate_message_name!(message_name)
|
24
24
|
end
|
25
25
|
|
26
26
|
def check_stream_existance
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
return if File.exist?(file_path)
|
28
|
+
|
29
|
+
raise Polyn::Cli::Error,
|
30
|
+
"You must first create a stream configuration with "\
|
31
|
+
"`polyn gen:stream #{format_stream_name}`"
|
32
32
|
end
|
33
33
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
def check_schema
|
35
|
+
return if File.exist?(File.join(options.dir, "schemas", "#{message_name}.json"))
|
36
|
+
|
37
|
+
raise Polyn::Cli::Error,
|
38
|
+
"You must first create a schema with `polyn gen:schema #{message_name}`"
|
39
39
|
end
|
40
40
|
|
41
41
|
def format_stream_name
|
@@ -45,8 +45,8 @@ module Polyn
|
|
45
45
|
def consumer_name
|
46
46
|
dest = Polyn::Cli::Naming.colon_to_underscore(destination_name)
|
47
47
|
dest = Polyn::Cli::Naming.dot_to_underscore(dest)
|
48
|
-
|
49
|
-
"#{dest}_#{
|
48
|
+
name = Polyn::Cli::Naming.dot_to_underscore(message_name)
|
49
|
+
"#{dest}_#{name}"
|
50
50
|
end
|
51
51
|
|
52
52
|
def file_name
|
@@ -65,7 +65,7 @@ module Polyn
|
|
65
65
|
stream_id = jetstream_stream.#{stream_name}.id
|
66
66
|
durable_name = "#{consumer_name}"
|
67
67
|
deliver_all = true
|
68
|
-
filter_subject = "#{
|
68
|
+
filter_subject = "#{message_name}"
|
69
69
|
sample_freq = 100
|
70
70
|
}
|
71
71
|
TF
|
data/lib/polyn/cli/naming.rb
CHANGED
@@ -10,10 +10,10 @@ module Polyn
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.validate_stream_name!(name)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
return if name.match(/^[a-zA-Z0-9_]+$/)
|
14
|
+
|
15
|
+
raise Polyn::Cli::Error,
|
16
|
+
"Stream name must be all alphanumeric, uppercase, and underscore separated. Got #{name}"
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.format_stream_name(name)
|
@@ -21,17 +21,17 @@ module Polyn
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def self.validate_destination_name!(name)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
return if name.is_a?(String) && name.match?(/\A[a-z0-9]+(?:(?:\.|:)[a-z0-9]+)*\z/)
|
25
|
+
|
26
|
+
raise Polyn::Cli::Error,
|
27
|
+
"Message destination must be lowercase, alphanumeric and dot/colon separated, got #{name}"
|
28
28
|
end
|
29
29
|
|
30
|
-
def self.
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
30
|
+
def self.validate_message_name!(name)
|
31
|
+
return if name.is_a?(String) && name.match?(/\A[a-z0-9]+(?:\.[a-z0-9]+)*\z/)
|
32
|
+
|
33
|
+
raise Polyn::Cli::Error,
|
34
|
+
"Message names must be lowercase, alphanumeric and dot separated"
|
35
35
|
end
|
36
36
|
|
37
37
|
def self.dot_to_underscore(name)
|
@@ -3,43 +3,43 @@
|
|
3
3
|
module Polyn
|
4
4
|
class Cli
|
5
5
|
##
|
6
|
-
# Generates a new JSON Schema file for
|
6
|
+
# Generates a new JSON Schema file for a message
|
7
7
|
class SchemaGenerator < Thor::Group
|
8
8
|
include Thor::Actions
|
9
9
|
|
10
|
-
desc "Generates a new JSON Schema file for
|
10
|
+
desc "Generates a new JSON Schema file for a message"
|
11
11
|
|
12
|
-
argument :
|
12
|
+
argument :message_name, required: true
|
13
13
|
class_option :dir, default: Dir.getwd
|
14
14
|
|
15
15
|
source_root File.join(File.expand_path(__dir__), "../templates")
|
16
16
|
|
17
|
-
def
|
18
|
-
@
|
17
|
+
def name
|
18
|
+
@name ||= message_name.split("/").last
|
19
19
|
end
|
20
20
|
|
21
21
|
def subdir
|
22
22
|
@subdir ||= begin
|
23
|
-
split =
|
23
|
+
split = message_name.split("/") - [name]
|
24
24
|
split.join("/")
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
def check_name
|
29
|
-
Polyn::Cli::Naming.
|
29
|
+
Polyn::Cli::Naming.validate_message_name!(name)
|
30
30
|
end
|
31
31
|
|
32
32
|
def file_name
|
33
|
-
@file_name ||= File.join(subdir, "#{
|
33
|
+
@file_name ||= File.join(subdir, "#{name}.json")
|
34
34
|
end
|
35
35
|
|
36
36
|
def schema_id
|
37
|
-
Polyn::Cli::Naming.dot_to_colon(
|
37
|
+
Polyn::Cli::Naming.dot_to_colon(name)
|
38
38
|
end
|
39
39
|
|
40
40
|
def create
|
41
41
|
say "Creating new schema for #{file_name}"
|
42
|
-
template "generators/schema.json", File.join(options.dir, "
|
42
|
+
template "generators/schema.json", File.join(options.dir, "schemas/#{file_name}")
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
@@ -3,17 +3,17 @@
|
|
3
3
|
module Polyn
|
4
4
|
class Cli
|
5
5
|
##
|
6
|
-
# Loads the JSON
|
6
|
+
# Loads the JSON schema into the schema registry.
|
7
7
|
class SchemaLoader
|
8
8
|
include Thor::Actions
|
9
9
|
|
10
10
|
STORE_NAME = "POLYN_SCHEMAS"
|
11
11
|
|
12
12
|
##
|
13
|
-
# Loads the
|
13
|
+
# Loads the schemas from the schema repository into the Polyn schema registry.
|
14
14
|
# @return [Bool]
|
15
15
|
def self.load(cli)
|
16
|
-
new(cli).
|
16
|
+
new(cli).load_schemas
|
17
17
|
end
|
18
18
|
|
19
19
|
def initialize(thor, **opts)
|
@@ -21,22 +21,21 @@ module Polyn
|
|
21
21
|
@client = connect
|
22
22
|
@store_name = opts.fetch(:store_name, STORE_NAME)
|
23
23
|
@bucket = client.key_value(@store_name)
|
24
|
-
@
|
25
|
-
@
|
26
|
-
@
|
27
|
-
@existing_events = {}
|
24
|
+
@schemas_dir = opts.fetch(:schemas_dir, File.join(Dir.pwd, "schemas"))
|
25
|
+
@schemas = {}
|
26
|
+
@existing_schemas = {}
|
28
27
|
end
|
29
28
|
|
30
|
-
def
|
31
|
-
thor.say "Loading
|
32
|
-
|
33
|
-
|
29
|
+
def load_schemas
|
30
|
+
thor.say "Loading schemas into the Polyn schema registry from '#{schemas_dir}'"
|
31
|
+
read_schemas
|
32
|
+
load_existing_schemas
|
34
33
|
|
35
|
-
|
36
|
-
bucket.put(name, JSON.generate(
|
34
|
+
schemas.each do |name, schema|
|
35
|
+
bucket.put(name, JSON.generate(schema))
|
37
36
|
end
|
38
37
|
|
39
|
-
|
38
|
+
delete_missing_schemas
|
40
39
|
|
41
40
|
true
|
42
41
|
end
|
@@ -44,13 +43,12 @@ module Polyn
|
|
44
43
|
private
|
45
44
|
|
46
45
|
attr_reader :thor,
|
47
|
-
:
|
46
|
+
:schemas,
|
48
47
|
:client,
|
49
48
|
:bucket,
|
50
|
-
:
|
51
|
-
:events_dir,
|
49
|
+
:schemas_dir,
|
52
50
|
:store_name,
|
53
|
-
:
|
51
|
+
:existing_schemas
|
54
52
|
|
55
53
|
def connect
|
56
54
|
opts = {
|
@@ -66,68 +64,59 @@ module Polyn
|
|
66
64
|
NATS.connect(opts).jetstream
|
67
65
|
end
|
68
66
|
|
69
|
-
def
|
70
|
-
|
71
|
-
|
67
|
+
def read_schemas
|
68
|
+
schema_files = Dir.glob(File.join(schemas_dir, "/**/*.json"))
|
69
|
+
validate_unique_schema_names!(schema_files)
|
72
70
|
|
73
|
-
|
74
|
-
thor.say "Loading '
|
75
|
-
|
76
|
-
|
77
|
-
validate_schema!(
|
78
|
-
Polyn::Cli::Naming.
|
79
|
-
schema = compose_cloud_event(data_schema)
|
71
|
+
schema_files.each do |schema_file|
|
72
|
+
thor.say "Loading 'schema #{schema_file}'"
|
73
|
+
schema = JSON.parse(File.read(schema_file))
|
74
|
+
schema_name = File.basename(schema_file, ".json")
|
75
|
+
validate_schema!(schema_name, schema)
|
76
|
+
Polyn::Cli::Naming.validate_message_name!(schema_name)
|
80
77
|
|
81
|
-
|
78
|
+
schemas[schema_name] = schema
|
82
79
|
end
|
83
80
|
end
|
84
81
|
|
85
|
-
def
|
86
|
-
duplicates = find_duplicates(
|
82
|
+
def validate_unique_schema_names!(schema_files)
|
83
|
+
duplicates = find_duplicates(schema_files)
|
87
84
|
return if duplicates.empty?
|
88
85
|
|
89
|
-
messages = duplicates.reduce([]) do |memo, (
|
90
|
-
memo << [
|
86
|
+
messages = duplicates.reduce([]) do |memo, (schema_name, files)|
|
87
|
+
memo << [schema_name, *files].join("\n")
|
91
88
|
end
|
92
89
|
message = [
|
93
|
-
"There can only be one of each
|
90
|
+
"There can only be one of each schema name. The following schemas were duplicated:",
|
94
91
|
*messages,
|
95
92
|
].join("\n")
|
96
93
|
raise Polyn::Cli::ValidationError, message
|
97
94
|
end
|
98
95
|
|
99
|
-
def find_duplicates(
|
100
|
-
|
101
|
-
File.basename(
|
96
|
+
def find_duplicates(schema_files)
|
97
|
+
schema_names = schema_files.group_by do |schema_file|
|
98
|
+
File.basename(schema_file, ".json")
|
102
99
|
end
|
103
|
-
|
104
|
-
hash[
|
100
|
+
schema_names.each_with_object({}) do |(schema_name, files), hash|
|
101
|
+
hash[schema_name] = files if files.length > 1
|
105
102
|
hash
|
106
103
|
end
|
107
104
|
end
|
108
105
|
|
109
|
-
def validate_schema!(
|
106
|
+
def validate_schema!(schema_name, schema)
|
110
107
|
JSONSchemer.schema(schema)
|
111
108
|
rescue StandardError => e
|
112
109
|
raise Polyn::Cli::ValidationError,
|
113
|
-
"Invalid JSON Schema document for event #{
|
110
|
+
"Invalid JSON Schema document for event #{schema_name}\n#{e.message}\n"\
|
114
111
|
"#{JSON.pretty_generate(schema)}"
|
115
112
|
end
|
116
113
|
|
117
|
-
def
|
118
|
-
cloud_event_schema.merge({
|
119
|
-
"definitions" => cloud_event_schema["definitions"].merge({
|
120
|
-
"datadef" => event_schema,
|
121
|
-
}),
|
122
|
-
})
|
123
|
-
end
|
124
|
-
|
125
|
-
def load_existing_events
|
114
|
+
def load_existing_schemas
|
126
115
|
sub = client.subscribe("#{key_prefix}.>")
|
127
116
|
|
128
117
|
loop do
|
129
|
-
msg
|
130
|
-
|
118
|
+
msg = sub.next_msg
|
119
|
+
existing_schemas[msg.subject.gsub("#{key_prefix}.", "")] = msg.data unless msg.data.empty?
|
131
120
|
# A timeout is the only mechanism given to indicate there are no
|
132
121
|
# more messages
|
133
122
|
rescue NATS::IO::Timeout
|
@@ -140,11 +129,11 @@ module Polyn
|
|
140
129
|
"$KV.#{store_name}"
|
141
130
|
end
|
142
131
|
|
143
|
-
def
|
144
|
-
|
145
|
-
|
146
|
-
thor.say "Deleting
|
147
|
-
bucket.delete(
|
132
|
+
def delete_missing_schemas
|
133
|
+
missing_schemas = existing_schemas.keys - schemas.keys
|
134
|
+
missing_schemas.each do |schema|
|
135
|
+
thor.say "Deleting schema #{schema}"
|
136
|
+
bucket.delete(schema)
|
148
137
|
end
|
149
138
|
end
|
150
139
|
end
|
data/lib/polyn/cli/version.rb
CHANGED
data/lib/polyn/cli.rb
CHANGED
@@ -8,7 +8,6 @@ require "polyn/cli/consumer_generator"
|
|
8
8
|
require "polyn/cli/naming"
|
9
9
|
require "polyn/cli/schema_generator"
|
10
10
|
require "polyn/cli/stream_generator"
|
11
|
-
require "polyn/cli/cloud_event"
|
12
11
|
require "polyn/cli/schema_loader"
|
13
12
|
require "polyn/cli/version"
|
14
13
|
require "json"
|
@@ -48,11 +47,11 @@ module Polyn
|
|
48
47
|
end
|
49
48
|
|
50
49
|
method_option :dir, default: Dir.getwd
|
51
|
-
desc "init", "initializes a Polyn
|
50
|
+
desc "init", "initializes a Polyn schema repository"
|
52
51
|
def init
|
53
|
-
say "Initializing Polyn
|
52
|
+
say "Initializing Polyn schema repository"
|
54
53
|
directory "tf", File.join(options.dir, "tf")
|
55
|
-
directory "
|
54
|
+
directory "schemas", File.join(options.dir, "schemas")
|
56
55
|
template "docker-compose.yml", File.join(options.dir, "docker-compose.yml")
|
57
56
|
template "Dockerfile", File.join(options.dir, "Dockerfile")
|
58
57
|
template ".dockerignore", File.join(options.dir, ".dockerignore")
|
@@ -91,7 +90,7 @@ module Polyn
|
|
91
90
|
end
|
92
91
|
end
|
93
92
|
|
94
|
-
desc "up", "updates the JetStream streams and consumers, as well the Polyn
|
93
|
+
desc "up", "updates the JetStream streams and consumers, as well the Polyn schema registry"
|
95
94
|
def up
|
96
95
|
terraform_root = File.join(Dir.getwd, "tf")
|
97
96
|
# We only want to run nats in the docker container if
|
@@ -110,8 +109,8 @@ module Polyn
|
|
110
109
|
end
|
111
110
|
end
|
112
111
|
|
113
|
-
say "Updating Polyn
|
114
|
-
Polyn::Cli::SchemaLoader.new(self).
|
112
|
+
say "Updating Polyn schema registry"
|
113
|
+
Polyn::Cli::SchemaLoader.new(self).load_schemas
|
115
114
|
end
|
116
115
|
|
117
116
|
private
|
@@ -158,12 +157,12 @@ module Polyn
|
|
158
157
|
remove_file File.join(tf_root, "backend.tf")
|
159
158
|
end
|
160
159
|
|
161
|
-
register(Polyn::Cli::SchemaGenerator, "gen:schema", "gen:schema
|
162
|
-
"Generates a new JSON Schema file for an
|
163
|
-
register(Polyn::Cli::StreamGenerator, "gen:stream", "gen:stream
|
160
|
+
register(Polyn::Cli::SchemaGenerator, "gen:schema", "gen:schema SCHEMA_NAME",
|
161
|
+
"Generates a new JSON Schema file for an schema")
|
162
|
+
register(Polyn::Cli::StreamGenerator, "gen:stream", "gen:stream SCHEMA_NAME",
|
164
163
|
"Generates a new stream configuration with boilerplate")
|
165
164
|
register(Polyn::Cli::ConsumerGenerator, "gen:consumer",
|
166
|
-
"gen:consumer STREAM_NAME DESTINATION_NAME
|
165
|
+
"gen:consumer STREAM_NAME DESTINATION_NAME SCHEMA_NAME",
|
167
166
|
"Generates a new NATS Consumer configuration with boilerplate")
|
168
167
|
end
|
169
168
|
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
# Polyn
|
1
|
+
# Polyn Schemas Repository
|
2
2
|
|
3
|
-
This repository contains all of the
|
3
|
+
This repository contains all of the schemas and terraform resources for the Polyn services
|
4
4
|
environment.
|
5
5
|
|
6
6
|
1. Install [Ruby](https://github.com/asdf-vm/asdf-ruby)
|
@@ -11,7 +11,7 @@ environment.
|
|
11
11
|
5. Ensure Docker & Docker Compose is installed
|
12
12
|
6. Call `bundle exec polyn tf_init` if this is the first time using terraform in the codebase.
|
13
13
|
7. Call `bundle exec polyn up`. By default this will run in `development` mode, which will start the NATS
|
14
|
-
server, configure it via Terraform, and update the Polyn
|
14
|
+
server, configure it via Terraform, and update the Polyn Schema Registry.
|
15
15
|
|
16
16
|
### Running NATS locally
|
17
17
|
|
@@ -29,40 +29,35 @@ Each stream should have its own configuration file under `./tf`. Run `bundle exe
|
|
29
29
|
|
30
30
|
Run `bundle exec polyn gen:consumer <stream_name> <destination_name> <event_type>` to generate new configuration for a consumer of a stream. It will be included in the same file as the stream configuration.
|
31
31
|
|
32
|
-
##
|
32
|
+
## Message Schemas
|
33
33
|
|
34
|
-
Run `bundle exec polyn gen:schema <
|
34
|
+
Run `bundle exec polyn gen:schema <schema_name>` to generate a new JSON Schema for a message
|
35
35
|
|
36
|
-
All the schemas for your
|
37
|
-
The name of your schema file should be the same as your
|
38
|
-
So if you have an
|
36
|
+
All the schemas for your messages should live in the `./schemas` directory.
|
37
|
+
The name of your schema file should be the same as your message, but with `.json` at the end.
|
38
|
+
So if you have an message called `widgets.created.v1` you would create a schema file called `widgets.created.v1.json` in the `./schemas` directory.
|
39
39
|
Every schema should be a valid [JSON Schema](https://json-schema.org/) document.
|
40
|
-
The Polyn CLI tool will combine your
|
40
|
+
The Polyn CLI tool will combine your message schema with the [Cloud Events Schema](https://cloudevents.io/) when it adds it to the Polyn Schema Registry.
|
41
41
|
This means you only need to include the JSON Schema for the `data` portion of the Cloud Event and not the entire Cloud Event schema.
|
42
42
|
|
43
43
|
### Subdirectories
|
44
44
|
|
45
|
-
If you'd like to organize your
|
45
|
+
If you'd like to organize your messages by team ownership or some other convention, you can use subdirectories to do so. The full message name should still be part of the file name. You should also ensure there are not duplicate schema names in different directories as only one schema can be defined per message name.
|
46
46
|
|
47
47
|
You can generate a schema in a subdirectory like this: `bundle exec polyn gen:schema some/nested/dir/widgets.created.v1`
|
48
48
|
|
49
49
|
## Schema Versioning
|
50
50
|
|
51
|
-
### New
|
51
|
+
### New Message
|
52
52
|
|
53
|
-
A new
|
53
|
+
A new message schema file should be a lower-case, dot-separated, name with a `v1` suffix
|
54
54
|
|
55
|
-
### Existing
|
55
|
+
### Existing Message
|
56
56
|
|
57
|
-
Existing
|
58
|
-
Backwards-compatibile meaning that any services Producing or Consuming the
|
59
|
-
Polyn Event Registry is updated with the change. There are many ways to make breaking change and so you should be
|
60
|
-
careful when you do this.
|
57
|
+
Existing message schemas can be changed without updating the file name if the change is backwards-compatible.
|
58
|
+
Backwards-compatibile meaning that any services Producing or Consuming the message will not break or be invalid when the Polyn Schema Registry is updated with the change. There are many ways to make breaking change and so you should be careful when you do this.
|
61
59
|
|
62
|
-
Making a change to
|
63
|
-
json file. The new file should have the same name as your old file, but with the version number increased. Your
|
64
|
-
Producers will need to continue producing both events until you are sure there are no more consumers using the
|
65
|
-
old event.
|
60
|
+
Making a change to a message schema that is not backwards-compatible will require you to create a brand new json file. The new file should have the same name as your old file, but with the version number increased. Your Producers will need to continue producing both message versions until you are sure there are no more consumers using the old message.
|
66
61
|
|
67
62
|
## Terraform State
|
68
63
|
|
@@ -74,7 +69,7 @@ For local development Polyn expects the `terraform.tfstate` file to exist in the
|
|
74
69
|
|
75
70
|
### Production
|
76
71
|
|
77
|
-
In production Terraform recommends keeping `terraform.tfstate` in a [remote storage location](https://www.terraform.io/language/state). The remote state file should be the "source of truth" for your infrastucture and shouldn't be getting accessed during development. Depending on the size of your organization and security policies, not all developers will have access to the remote storage source and you don't want that to prohibit them from adding
|
72
|
+
In production Terraform recommends keeping `terraform.tfstate` in a [remote storage location](https://www.terraform.io/language/state). The remote state file should be the "source of truth" for your infrastucture and shouldn't be getting accessed during development. Depending on the size of your organization and security policies, not all developers will have access to the remote storage source and you don't want that to prohibit them from adding schemas, streams, or consumers.
|
78
73
|
|
79
74
|
Polyn expects you to keep a `./remote_state_config/backend.tf` file that configures a Terraform [backend](https://www.terraform.io/language/settings/backends/configuration). This will only be used when `POLYN_ENV=production`.
|
80
75
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
{
|
2
|
+
"$id": "money:amount:v1",
|
3
|
+
"type": "object",
|
4
|
+
"properties": {
|
5
|
+
"currency": {
|
6
|
+
"type": "string",
|
7
|
+
"description": "currency code for the amount"
|
8
|
+
},
|
9
|
+
"amount": {
|
10
|
+
"type": "number",
|
11
|
+
"description": "amount of money"
|
12
|
+
}
|
13
|
+
},
|
14
|
+
"required": ["currency", "amount"]
|
15
|
+
}
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: polyn-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jarod
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-
|
12
|
+
date: 2022-12-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: dotenv
|
@@ -91,7 +91,6 @@ files:
|
|
91
91
|
- bin/setup
|
92
92
|
- exe/polyn
|
93
93
|
- lib/polyn/cli.rb
|
94
|
-
- lib/polyn/cli/cloud_event.rb
|
95
94
|
- lib/polyn/cli/configuration.rb
|
96
95
|
- lib/polyn/cli/consumer_generator.rb
|
97
96
|
- lib/polyn/cli/naming.rb
|
@@ -99,17 +98,16 @@ files:
|
|
99
98
|
- lib/polyn/cli/schema_loader.rb
|
100
99
|
- lib/polyn/cli/stream_generator.rb
|
101
100
|
- lib/polyn/cli/version.rb
|
102
|
-
- lib/polyn/cloud-event-schema.json
|
103
101
|
- lib/polyn/templates/.dockerignore
|
104
102
|
- lib/polyn/templates/.gitignore
|
105
103
|
- lib/polyn/templates/Dockerfile
|
106
104
|
- lib/polyn/templates/Gemfile
|
107
105
|
- lib/polyn/templates/README.md
|
108
106
|
- lib/polyn/templates/docker-compose.yml
|
109
|
-
- lib/polyn/templates/events/.gitkeep
|
110
|
-
- lib/polyn/templates/events/widgets.created.v1.json
|
111
107
|
- lib/polyn/templates/generators/schema.json
|
112
108
|
- lib/polyn/templates/generators/stream.tf
|
109
|
+
- lib/polyn/templates/schemas/money.amount.v1.json
|
110
|
+
- lib/polyn/templates/schemas/widgets.created.v1.json
|
113
111
|
- lib/polyn/templates/tf/kv_buckets.tf
|
114
112
|
- lib/polyn/templates/tf/provider.tf
|
115
113
|
- lib/polyn/templates/tf/remote_state_config/backend.tf
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Polyn
|
4
|
-
class Cli
|
5
|
-
##
|
6
|
-
# Access cloud event information
|
7
|
-
class CloudEvent
|
8
|
-
def self.to_h
|
9
|
-
path = File.expand_path(File.join(File.dirname(__FILE__), "../cloud-event-schema.json"))
|
10
|
-
file = File.open(path)
|
11
|
-
JSON.parse(file.read)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,187 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
3
|
-
"description": "CloudEvents Specification JSON Schema, extended for Polyn",
|
4
|
-
"type": "object",
|
5
|
-
"properties": {
|
6
|
-
"id": {
|
7
|
-
"description": "Identifies the event.",
|
8
|
-
"$ref": "#/definitions/iddef",
|
9
|
-
"examples": [
|
10
|
-
"A234-1234-1234"
|
11
|
-
]
|
12
|
-
},
|
13
|
-
"source": {
|
14
|
-
"description": "Identifies the context in which an event happened.",
|
15
|
-
"$ref": "#/definitions/sourcedef",
|
16
|
-
"examples" : [
|
17
|
-
"https://github.com/cloudevents",
|
18
|
-
"mailto:cncf-wg-serverless@lists.cncf.io",
|
19
|
-
"urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66",
|
20
|
-
"cloudevents/spec/pull/123",
|
21
|
-
"/sensors/tn-1234567/alerts",
|
22
|
-
"1-555-123-4567"
|
23
|
-
]
|
24
|
-
},
|
25
|
-
"specversion": {
|
26
|
-
"description": "The version of the CloudEvents specification which the event uses.",
|
27
|
-
"$ref": "#/definitions/specversiondef",
|
28
|
-
"examples": [
|
29
|
-
"1.0"
|
30
|
-
]
|
31
|
-
},
|
32
|
-
"type": {
|
33
|
-
"description": "Describes the type of event related to the originating occurrence.",
|
34
|
-
"$ref": "#/definitions/typedef",
|
35
|
-
"examples" : [
|
36
|
-
"com.github.pull_request.opened",
|
37
|
-
"com.example.object.deleted.v2"
|
38
|
-
]
|
39
|
-
},
|
40
|
-
"datacontenttype": {
|
41
|
-
"description": "Content type of the data value. Must adhere to RFC 2046 format.",
|
42
|
-
"$ref": "#/definitions/datacontenttypedef",
|
43
|
-
"examples": [
|
44
|
-
"text/xml",
|
45
|
-
"application/json",
|
46
|
-
"image/png",
|
47
|
-
"multipart/form-data"
|
48
|
-
]
|
49
|
-
},
|
50
|
-
"dataschema": {
|
51
|
-
"description": "Identifies the schema that data adheres to.",
|
52
|
-
"$ref": "#/definitions/dataschemadef"
|
53
|
-
},
|
54
|
-
"subject": {
|
55
|
-
"description": "Describes the subject of the event in the context of the event producer (identified by source).",
|
56
|
-
"$ref": "#/definitions/subjectdef",
|
57
|
-
"examples": [
|
58
|
-
"mynewfile.jpg"
|
59
|
-
]
|
60
|
-
},
|
61
|
-
"time": {
|
62
|
-
"description": "Timestamp of when the occurrence happened. Must adhere to RFC 3339.",
|
63
|
-
"$ref": "#/definitions/timedef",
|
64
|
-
"examples": [
|
65
|
-
"2018-04-05T17:31:00Z"
|
66
|
-
]
|
67
|
-
},
|
68
|
-
"data": {
|
69
|
-
"description": "The event payload.",
|
70
|
-
"$ref": "#/definitions/datadef",
|
71
|
-
"examples": [
|
72
|
-
"<much wow=\"xml\"/>"
|
73
|
-
]
|
74
|
-
},
|
75
|
-
"data_base64": {
|
76
|
-
"description": "Base64 encoded event payload. Must adhere to RFC4648.",
|
77
|
-
"$ref": "#/definitions/data_base64def",
|
78
|
-
"examples": [
|
79
|
-
"Zm9vYg=="
|
80
|
-
]
|
81
|
-
},
|
82
|
-
"polyndata": {
|
83
|
-
"$ref": "#/definitions/polyndatadef",
|
84
|
-
"description": "Information about the client that produced the event and additional metadata",
|
85
|
-
"examples": [
|
86
|
-
{
|
87
|
-
"clientlang": "elixir",
|
88
|
-
"clientlangversion": "1.13.2",
|
89
|
-
"clientversion": "0.1.0"
|
90
|
-
}
|
91
|
-
]
|
92
|
-
},
|
93
|
-
"polyntrace": {
|
94
|
-
"$ref": "#/definitions/polyntracedef",
|
95
|
-
"description": "Previous events that led to this one",
|
96
|
-
"examples": [
|
97
|
-
[
|
98
|
-
{
|
99
|
-
"type": "<topic>",
|
100
|
-
"time": "2018-04-05T17:31:00Z",
|
101
|
-
"id": "<uuid>"
|
102
|
-
}
|
103
|
-
]
|
104
|
-
]
|
105
|
-
}
|
106
|
-
},
|
107
|
-
"required": ["id", "source", "specversion", "type"],
|
108
|
-
"definitions": {
|
109
|
-
"iddef": {
|
110
|
-
"type": "string",
|
111
|
-
"minLength": 1
|
112
|
-
},
|
113
|
-
"sourcedef": {
|
114
|
-
"type": "string",
|
115
|
-
"format": "uri-reference",
|
116
|
-
"minLength": 1
|
117
|
-
},
|
118
|
-
"specversiondef": {
|
119
|
-
"type": "string",
|
120
|
-
"minLength": 1
|
121
|
-
},
|
122
|
-
"typedef": {
|
123
|
-
"type": "string",
|
124
|
-
"minLength": 1
|
125
|
-
},
|
126
|
-
"datacontenttypedef": {
|
127
|
-
"type": ["string", "null"],
|
128
|
-
"minLength": 1
|
129
|
-
},
|
130
|
-
"dataschemadef": {
|
131
|
-
"type": ["string", "null"],
|
132
|
-
"format": "uri",
|
133
|
-
"minLength": 1
|
134
|
-
},
|
135
|
-
"subjectdef": {
|
136
|
-
"type": ["string", "null"],
|
137
|
-
"minLength": 1
|
138
|
-
},
|
139
|
-
"timedef": {
|
140
|
-
"type": ["string", "null"],
|
141
|
-
"format": "date-time",
|
142
|
-
"minLength": 1
|
143
|
-
},
|
144
|
-
"datadef": {
|
145
|
-
"type": ["object", "string", "number", "array", "boolean", "null"]
|
146
|
-
},
|
147
|
-
"data_base64def": {
|
148
|
-
"type": ["string", "null"],
|
149
|
-
"contentEncoding": "base64"
|
150
|
-
},
|
151
|
-
"polyndatadef": {
|
152
|
-
"type": "object",
|
153
|
-
"properties": {
|
154
|
-
"clientlang": {
|
155
|
-
"type": "string"
|
156
|
-
},
|
157
|
-
"clientlangversion": {
|
158
|
-
"type": "string"
|
159
|
-
},
|
160
|
-
"clientversion": {
|
161
|
-
"type": "string"
|
162
|
-
}
|
163
|
-
},
|
164
|
-
"required": ["clientlang", "clientlangversion", "clientversion"]
|
165
|
-
},
|
166
|
-
"polyntracedef": {
|
167
|
-
"type" : "array",
|
168
|
-
"items": {
|
169
|
-
"type": "object",
|
170
|
-
"properties": {
|
171
|
-
"type": {
|
172
|
-
"type": "string"
|
173
|
-
},
|
174
|
-
"time": {
|
175
|
-
"type": "string",
|
176
|
-
"format": "date-time"
|
177
|
-
},
|
178
|
-
"id" : {
|
179
|
-
"type": "string",
|
180
|
-
"format": "uuid"
|
181
|
-
}
|
182
|
-
},
|
183
|
-
"required": ["type", "time", "id"]
|
184
|
-
}
|
185
|
-
}
|
186
|
-
}
|
187
|
-
}
|
File without changes
|