shred 0.0.4 → 0.0.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b2e054fbed6a3aea3fa024120dc4f04ab56b8d11
4
- data.tar.gz: fb5a6578711711182bce19418638681f09336a31
3
+ metadata.gz: d94a83bf54dff1959be163040d2703457f1b6777
4
+ data.tar.gz: 99aa30b2a973d733eb52c258dfd18dd3ff80a752
5
5
  SHA512:
6
- metadata.gz: 766546e3f1b2d13863dab3658da6809487569516f8c12319ede06c5e19473ee0dd8b57dee953fc2d327344f4b844882d5370dc6cd49dc02b35cc1ef40c4c477f
7
- data.tar.gz: 84d5c56ea550317e12c2d772cbf1b7ea744858dfb7bba05746d20d40ead486b329b530fdad88fe74c97f805f847cd8049b755f20f40f7ebb57de135adc48a50d
6
+ metadata.gz: 675abe608dbbdd741e6ec746cbb44a8c5236af20a7138b176fedebd8c1fb4b5ab639c07fccbe4bf257b1264d9f012168045ad3b90af9383a47d982b234c99252
7
+ data.tar.gz: 965952a420c451921659a40dd8739e8edac1fe931344f97e7c16853180109fd5818eb26477a10cbac289bd47d1fc0890de09cff2a3b352bd80a1bf90c7f49e86
@@ -167,6 +167,25 @@ module Shred
167
167
  value
168
168
  end
169
169
 
170
+ def interpolate_value(value, context: {})
171
+ value.gsub(/{[^}]+}/) do |match|
172
+ ref = match.slice(1, match.length)
173
+ ref = ref.slice(0, ref.length - 1)
174
+ if ref =~ /^env\:(.+)$/
175
+ env_key = $1.upcase
176
+ if ENV.key?(env_key)
177
+ ENV[env_key]
178
+ else
179
+ raise "Unset environment variable '#{env_key}' referenced by value '#{value}'"
180
+ end
181
+ elsif context.key?(ref.to_sym)
182
+ context[ref.to_sym]
183
+ else
184
+ raise "Unknown interpolation variable '#{ref}' referenced by value '#{value}'"
185
+ end
186
+ end
187
+ end
188
+
170
189
  def run_shell_command(command)
171
190
  ShellCommandRunner.new(console: console).run(command)
172
191
  end
@@ -9,7 +9,7 @@ module Shred
9
9
  LONGDESC
10
10
  def init
11
11
  run_shell_command(ShellCommand.new(
12
- command_lines: 'bin/rake db:create db:structure:load',
12
+ command_lines: 'bin/rake db:create:all db:structure:load',
13
13
  success_msg: 'Database initialized',
14
14
  error_msg: 'Database could not be initialized'
15
15
  ))
@@ -23,6 +23,27 @@ module Shred
23
23
  error_msg: 'Migrations could not be applied'
24
24
  ))
25
25
  end
26
+
27
+ desc 'dump', 'Dump the contents of the database to a file'
28
+ def dump
29
+ command_lines = Array(cfg('dump')).map { |v| interpolate_value(v) }
30
+ run_shell_command(ShellCommand.new(
31
+ command_lines: command_lines,
32
+ success_msg: 'Database dumped',
33
+ error_msg: 'Database could not be dumped'
34
+ ))
35
+ end
36
+
37
+ desc 'restore DUMPFILE', 'Load the contents of a dump file into the database'
38
+ def restore(dumpfile)
39
+ context = {dumpfile: dumpfile}
40
+ command_lines = Array(cfg('restore')).map { |v| interpolate_value(v, context: context) }
41
+ run_shell_command(ShellCommand.new(
42
+ command_lines: command_lines,
43
+ success_msg: 'Database restored',
44
+ error_msg: 'Database could not be restored'
45
+ ))
46
+ end
26
47
  end
27
48
  end
28
49
  end
@@ -1,6 +1,6 @@
1
- require 'shred/commands/base'
2
1
  require 'dotenv'
3
2
  require 'platform-api'
3
+ require 'shred/commands/base'
4
4
 
5
5
  module Shred
6
6
  module Commands
@@ -23,27 +23,32 @@ module Shred
23
23
 
24
24
  run_shell_command(ShellCommand.new(command_lines: 'heroku auth:whoami'))
25
25
 
26
- io = StringIO.new
26
+ heroku = StringIO.new
27
27
  run_shell_command(ShellCommand.new(
28
28
  command_lines: "heroku config --app #{app_name} --shell",
29
- output: io
29
+ output: heroku
30
30
  ))
31
31
 
32
- File.open('.env', 'w') do |output|
33
- io.string.split("\n").each do |line|
34
- if line =~ /^([^=]+)=/ && vars.include?($1)
35
- output.write("#{line}\n")
36
- end
32
+ outvars = {}
33
+
34
+ heroku.string.split("\n").each do |line|
35
+ key, value = line.split('=', 2)
36
+ outvars[key] = value if vars.include?(key)
37
+ end
38
+
39
+ if custom
40
+ custom.each do |key, value|
41
+ outvars[key] = interpolate_value(value)
37
42
  end
38
- console.say_ok("Heroku config written to .env")
43
+ end
39
44
 
40
- if custom
41
- custom.each do |key, value|
42
- output.write("#{key}=#{value}\n")
43
- end
44
- console.say_ok("Custom config written to .env")
45
+ File.open('.env', 'w') do |dotenv|
46
+ outvars.sort_by(&:first).each do |(key, value)|
47
+ dotenv.write("#{key}=#{value}\n")
45
48
  end
46
49
  end
50
+
51
+ console.say_ok("Heroku config written to .env")
47
52
  end
48
53
  end
49
54
  end
@@ -0,0 +1,67 @@
1
+ require 'dotenv'
2
+ require 'aws-sdk'
3
+ require 'shred/commands/base'
4
+
5
+ module Shred
6
+ module Commands
7
+ class DynamoDb < Base
8
+ desc 'mktable NAME REGION READ_UNITS WRITE_UNITS', 'Create a DynamoDB table'
9
+ long_desc <<-LONGDESC
10
+ Create a DynamoDB table with the given name in the given region with the given throughput capacity.
11
+
12
+ All values are used exactly as specified. They are *not* interpolated.
13
+ LONGDESC
14
+ option :pk, type: :string, default: 'id'
15
+ option :pk_type, type: :string, default: 'string'
16
+ def mktable(name, region, read_capacity_units, write_capacity_units)
17
+ ::Dotenv.load
18
+
19
+ create_table(name, region, read_capacity_units.to_i, write_capacity_units.to_i,
20
+ hash_key: {options[:pk] => options[:pk_type]})
21
+ end
22
+
23
+ desc 'mktables', 'Create all configured DynamoDB tables'
24
+ long_desc <<-LONGDESC
25
+ Create a DynamoDB table for each element of the `commands.dynamodb.tables` config var.
26
+
27
+ If the `commands.dynamodb.table_prefix` config var is set, its value is prepended to each table name.
28
+
29
+ Prefixed table names and region names are interpolated.
30
+ LONGDESC
31
+ def mktables
32
+ ::Dotenv.load
33
+
34
+ prefix = cfg('table_prefix', required: false)
35
+
36
+ cfg('tables').each do |(name, table_cfg)|
37
+ name = "#{prefix}#{name}" if prefix
38
+ name = interpolate_value(name)
39
+ region = interpolate_value(table_cfg['region'])
40
+ read_capacity_units = table_cfg['read_capacity_units'].to_i
41
+ write_capacity_units = table_cfg['write_capacity_units'].to_i
42
+ pk = table_cfg['primary_key'].fetch('name', 'id')
43
+ pk_type = table_cfg['primary_key'].fetch('type', 'string')
44
+
45
+ create_table(name, region, read_capacity_units, write_capacity_units, hash_key: {pk => pk_type})
46
+ end
47
+ end
48
+
49
+ no_commands do
50
+ def create_table(name, region, read_capacity_units, write_capacity_units, hash_key: nil)
51
+ ddb = AWS::DynamoDB.new(region: region)
52
+ if ddb.tables[name].exists?
53
+ console.say_ok("Dynamo DB table #{name} already exists in region #{region}")
54
+ else
55
+ table = ddb.tables.create(name, read_capacity_units, write_capacity_units, hash_key)
56
+ sleep 1 while table.status == :creating
57
+ if table.status == :active
58
+ console.say_ok("Created Dynamo DB table #{name} in region #{region}")
59
+ else
60
+ console.say_err("Failed to create Dynamo DB table #{name} in region #{region}: status #{table.status}")
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,119 @@
1
+ require 'dotenv'
2
+ require 'elasticsearch'
3
+ require 'shred/commands/base'
4
+
5
+ module Shred
6
+ module Commands
7
+ class Elasticsearch < Base
8
+ desc 'mkindex NAME', 'Create a search index'
9
+ long_desc <<-LONGDESC
10
+ Create the search index with the given name.
11
+
12
+ If the `commands.elasticsearch.indexes.<name>.create` config var is present, it is taken to specify a list
13
+ of shell commands to be used to create the index. This mode supports creating indices with custom mappings
14
+ or settings.
15
+
16
+ The index name is used exactly as specified; it is *not* interpolated. However, the shell commands *are*
17
+ interpolated.
18
+ LONGDESC
19
+ def mkindex(name)
20
+ ::Dotenv.load
21
+ create_index(name, cfg("indexes.#{name}", required: false))
22
+ end
23
+
24
+ desc 'mkindices', 'Create all configured search indexes'
25
+ long_desc <<-LONGDESC
26
+ Creates each search index listed for the `commands.elasticsearch.indexes` config var.
27
+
28
+ If the `commands.elasticsearch.indexes.<name>.create` config var is present, it is taken to specify a list
29
+ of shell commands to be used to create the index. This mode supports creating indices with custom mappings
30
+ or settings.
31
+
32
+ Each index name and shell command is interpolated.
33
+ LONGDESC
34
+ def mkindices
35
+ ::Dotenv.load
36
+ Array(cfg('indexes')).each do |name, index_cfg|
37
+ create_index(name, index_cfg)
38
+ end
39
+ end
40
+
41
+ desc 'rmindex NAME', 'Delete a search index'
42
+ long_desc <<-LONGDESC
43
+ Delete the search index with the given name.
44
+
45
+ The index name is used exactly as specified; it is *not* interpolated.
46
+ LONGDESC
47
+ def rmindex(name)
48
+ ::Dotenv.load
49
+ delete_index(name)
50
+ end
51
+
52
+ desc 'rmindices', 'Delete all configured search indexes'
53
+ long_desc <<-LONGDESC
54
+ Deletes each search index listed for the `commands.elasticsearch.indexes` config var.
55
+
56
+ Each index name is interpolated.
57
+ LONGDESC
58
+ def rmindices
59
+ ::Dotenv.load
60
+ Array(cfg('indexes').keys).each do |name|
61
+ delete_index(name)
62
+ end
63
+ end
64
+
65
+ desc 'import NAME', 'Import data into a search index'
66
+ long_desc <<-LONGDESC
67
+ Imports data into the search index with the given name.
68
+
69
+ Executes one or more shell commands taken from the `commands.elasticsearch.indexes.<name>.import` config var.
70
+
71
+ The index name is used exactly as specified; it is *not* interpolated. However, the shell commands *are*
72
+ interpolated.
73
+ LONGDESC
74
+ def import(name)
75
+ ::Dotenv.load
76
+ command_lines = Array(cfg("indexes.#{name}.import")).map { |l| interpolate_value(l) }
77
+ run_shell_command(ShellCommand.new(
78
+ command_lines: command_lines,
79
+ success_msg: "Data imported into index #{name}",
80
+ error_msg: "Failed to import data into index #{name}"
81
+ ))
82
+ end
83
+
84
+ no_commands do
85
+ def client
86
+ url = interpolate_value(cfg('url'))
87
+ @client ||= ::Elasticsearch::Client.new(url: url)
88
+ end
89
+
90
+ def create_index(name, index_cfg = nil)
91
+ if index_cfg && index_cfg['create']
92
+ command_lines = Array(index_cfg['create']).map { |l| interpolate_value(l) }
93
+ run_shell_command(ShellCommand.new(
94
+ command_lines: command_lines,
95
+ success_msg: "Created index #{name}",
96
+ error_msg: "Failed to create index #{name}"
97
+ ))
98
+ else
99
+ begin
100
+ client.indices.create(index: name)
101
+ console.say_ok("Created index #{name}")
102
+ rescue ::Elasticsearch::Transport::Transport::Errors::BadRequest => e
103
+ raise unless e.to_s =~ /IndexAlreadyExistsException/
104
+ console.say_err("Index #{name} already exists")
105
+ end
106
+ end
107
+ end
108
+
109
+ def delete_index(name)
110
+ client.indices.delete(index: name)
111
+ console.say_ok("Deleted index #{name}")
112
+ rescue ::Elasticsearch::Transport::Transport::Errors::NotFound => e
113
+ raise unless e.to_s =~ /IndexMissingException/
114
+ console.say_err("Index #{name} does not exist")
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,50 @@
1
+ require 'dotenv'
2
+ require 'aws-sdk'
3
+ require 'shred/commands/base'
4
+
5
+ module Shred
6
+ module Commands
7
+ class S3 < Base
8
+ desc 'mkbucket NAME REGION', 'Create an S3 bucket'
9
+ long_desc <<-LONGDESC
10
+ Create an S3 bucket with the given name in the given region.
11
+
12
+ The bucket and region names are used exactly as specified. They are *not* interpolated.
13
+ LONGDESC
14
+ def mkbucket(name, region)
15
+ ::Dotenv.load
16
+
17
+ create_bucket(name, region)
18
+ end
19
+
20
+ desc 'mkbuckets', 'Create all configured S3 buckets'
21
+ long_desc <<-LONGDESC
22
+ Create an S3 bucket for each element of the `commands.s3.buckets` config var.
23
+
24
+ Bucket and region names are interpolated.
25
+ LONGDESC
26
+ def mkbuckets
27
+ ::Dotenv.load
28
+
29
+ cfg('buckets').each do |(key, bucket_cfg)|
30
+ name = interpolate_value(bucket_cfg['name'])
31
+ region = interpolate_value(bucket_cfg['region'])
32
+
33
+ create_bucket(name, region)
34
+ end
35
+ end
36
+
37
+ no_commands do
38
+ def create_bucket(name, region)
39
+ s3 = AWS::S3.new(region: region)
40
+ if s3.buckets[name].exists?
41
+ console.say_ok("S3 bucket #{name} already exists in region #{region}")
42
+ else
43
+ s3.buckets.create(name)
44
+ console.say_ok("Created S3 bucket #{name} in region #{region}")
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
data/lib/shred/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Shred
2
- VERSION = '0.0.4'
2
+ VERSION = '0.0.5'
3
3
  end
data/lib/shred.rb CHANGED
@@ -2,10 +2,13 @@ require 'shred/commands/app'
2
2
  require 'shred/commands/db'
3
3
  require 'shred/commands/deploy'
4
4
  require 'shred/commands/dotenv'
5
+ require 'shred/commands/dynamo_db'
6
+ require 'shred/commands/elasticsearch'
5
7
  require 'shred/commands/js_deps'
6
8
  require 'shred/commands/platform_deps'
7
9
  require 'shred/commands/ruby_deps'
8
10
  require 'shred/commands/services'
11
+ require 'shred/commands/s3'
9
12
  require 'shred/commands/test'
10
13
  require 'shred/version'
11
14
  require 'thor'
@@ -43,13 +46,25 @@ module Shred
43
46
  subcommand 'js_deps', Commands::JsDeps
44
47
  end
45
48
  if commands.key?('db')
46
- desc 'db SUBCOMMAND ...ARGS', 'Manage the database'
49
+ desc 'db SUBCOMMAND ...ARGS', 'Manage the relational database system'
47
50
  subcommand 'db', Commands::Db
48
51
  end
49
52
  if commands.key?('dotenv')
50
53
  desc 'dotenv SUBCOMMAND ...ARGS', 'Manage the environmental configuration'
51
54
  subcommand 'dotenv', Commands::Dotenv
52
55
  end
56
+ if commands.key?('s3')
57
+ desc 's3 SUBCOMMAND ...ARGS', 'Manage Amazon S3 buckets'
58
+ subcommand 's3', Commands::S3
59
+ end
60
+ if commands.key?('dynamo_db')
61
+ desc 'dynamo_db SUBCOMMAND ...ARGS', 'Manage Amazon Dynamo DB tables'
62
+ subcommand 'dynamo_db', Commands::DynamoDb
63
+ end
64
+ if commands.key?('elasticsearch')
65
+ desc 'elasticsearch subcommand ...ARGS', 'Manage Elasticsearch indexes'
66
+ subcommand 'elasticsearch', Commands::Elasticsearch
67
+ end
53
68
  if commands.key?('test')
54
69
  desc 'test SUBCOMMAND ...ARGS', 'Run tests'
55
70
  subcommand 'test', Commands::Test
@@ -68,6 +83,7 @@ module Shred
68
83
  self.class.config['commands']['setup'].each do |(cmd, subcmd)|
69
84
  invoke(cmd.to_sym, [subcmd.to_sym])
70
85
  end
86
+ console.say_ok("Setup complete!")
71
87
  end
72
88
  end
73
89
  end
data/lib/shred.yml.tt CHANGED
@@ -3,6 +3,8 @@ commands:
3
3
  start:
4
4
  - foreman start
5
5
  db:
6
+ dump: pg_dump -Fc --no-acl --no-owner -h localhost <%= app_name %>_development > <%= app_name %>_development.dump
7
+ restore: pg_restore --verbose --clean --no-acl --no-owner -h localhost -d <%= app_name %>_development {dumpfile}
6
8
  deploy:
7
9
  default_environment: staging
8
10
  staging:
@@ -21,12 +23,42 @@ commands:
21
23
  app_name: <%= app_name %>-staging
22
24
  vars:
23
25
  - AIRBRAKE_API_KEY
26
+ - ELASTICSEARCH_URL
24
27
  custom:
25
28
  vars:
26
29
  RAILS_ENV: development
30
+ AWS_S3_BUCKET: <%= app_name %>-dev-{env:USER}
31
+ AWS_S3_REGION: us-west-2
32
+ AWS_DYNAMO_DB_REGION: us-west-2
33
+ dynamo_db:
34
+ table_prefix: 'dev-{env:USER}'
35
+ tables:
36
+ clicks:
37
+ region: '{env:AWS_DYNAMO_DB_REGION}'
38
+ primary_key:
39
+ name: uuid
40
+ type: string
41
+ read_capacity_units: 10
42
+ write_capacity_units: 10
43
+ impressions:
44
+ region: '{env:AWS_DYNAMO_DB_REGION}'
45
+ primary_key:
46
+ name: uuid
47
+ type: string
48
+ read_capacity_units: 10
49
+ write_capacity_units: 10
50
+ elasticsearch:
51
+ url: '{env:ELASTICSEARCH_URL}'
52
+ indexes:
53
+ stories-development:
54
+ create:
55
+ - thor stories:create
56
+ import:
57
+ - thor stories:index
27
58
  js_deps:
28
59
  platform_deps:
29
60
  homebrew:
61
+ - node
30
62
  - postgres
31
63
  - redis
32
64
  - heroku
@@ -53,6 +85,11 @@ commands:
53
85
  mailcatcher:
54
86
  start: mailcatcher
55
87
  stop: killall mailcatcher
88
+ s3:
89
+ buckets:
90
+ default:
91
+ name: '{env:AWS_S3_BUCKET}'
92
+ region: '{env:AWS_S3_REGION}'
56
93
  setup:
57
94
  platform_deps: install
58
95
  services: start
@@ -64,4 +101,4 @@ commands:
64
101
  server:
65
102
  - bin/rake spec
66
103
  client:
67
- - bin/rake teaspoon:run
104
+ - bin/rake teaspoon
data/shred.gemspec CHANGED
@@ -21,7 +21,9 @@ Gem::Specification.new do |spec|
21
21
  spec.add_development_dependency 'bundler', '~> 1.7'
22
22
  spec.add_development_dependency 'rake', '~> 10.0'
23
23
 
24
+ spec.add_dependency 'aws-sdk'
24
25
  spec.add_dependency 'dotenv'
26
+ spec.add_dependency 'elasticsearch'
25
27
  spec.add_dependency 'platform-api'
26
28
  spec.add_dependency 'thor'
27
29
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shred
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian
@@ -39,6 +39,20 @@ dependencies:
39
39
  - - ~>
40
40
  - !ruby/object:Gem::Version
41
41
  version: '10.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: aws-sdk
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
42
56
  - !ruby/object:Gem::Dependency
43
57
  name: dotenv
44
58
  requirement: !ruby/object:Gem::Requirement
@@ -53,6 +67,20 @@ dependencies:
53
67
  - - '>='
54
68
  - !ruby/object:Gem::Version
55
69
  version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: elasticsearch
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
56
84
  - !ruby/object:Gem::Dependency
57
85
  name: platform-api
58
86
  requirement: !ruby/object:Gem::Requirement
@@ -105,9 +133,12 @@ files:
105
133
  - lib/shred/commands/db.rb
106
134
  - lib/shred/commands/deploy.rb
107
135
  - lib/shred/commands/dotenv.rb
136
+ - lib/shred/commands/dynamo_db.rb
137
+ - lib/shred/commands/elasticsearch.rb
108
138
  - lib/shred/commands/js_deps.rb
109
139
  - lib/shred/commands/platform_deps.rb
110
140
  - lib/shred/commands/ruby_deps.rb
141
+ - lib/shred/commands/s3.rb
111
142
  - lib/shred/commands/services.rb
112
143
  - lib/shred/commands/test.rb
113
144
  - lib/shred/version.rb