founders_template 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d2b17da3d674c0c5b4d41ba46958fd0702cafd663753e32686cfae849343eb1
4
- data.tar.gz: c952aceb8edfd4b65ca351d2761585b2e3bccda6068e25154834e697c5c234c9
3
+ metadata.gz: 4f778c67aa0b23fdf70d7ee41b7e989a774e7a810ada15d2f805ddf47785aec5
4
+ data.tar.gz: b27060bdfec354a751932afb8ba2fed4252162cef4ea4fa1e507e7ff8b8ea841
5
5
  SHA512:
6
- metadata.gz: 543bd724960bbebcf8e53eaaa62128b2214517120df19b80469dbe03d009ca4fe46a2bcababc00216f675688b3350c26e44c21d7aa55a317dd270cca76fe59cb
7
- data.tar.gz: 9a07ada41185a2477c936c98a4b5cc26104b4bb08c5b669266f71a7bab0c626c1b13298f1e3aaab0b216c8f3f0c586b0405e270e6b705920da222e4549699b60
6
+ metadata.gz: b5ea28ed9b81d17c257a3202b801fe86e25a625cd9b2a3fd756c7334bbded7c1aef7aecaeae0703046d6ea216634cf4dc25cc2da6de4f37f52c8c5826449bde4
7
+ data.tar.gz: 88515689c9a372a5aa3cdd38e971ecf4b22b2a1300bb2c47600695d86c1631d4e099915382df9d20150afc8a408564d85c57e1b6bb6de3349ea42c4d4650bd14
data/.gitignore CHANGED
@@ -11,3 +11,4 @@
11
11
  .rspec_status
12
12
  vendor/
13
13
  .rubocop-*
14
+ playground/
@@ -1,13 +1,43 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- founders_template (0.1.2)
4
+ founders_template (0.1.3)
5
+ activesupport
6
+ aws-sdk-core
7
+ aws-sdk-ec2
8
+ aws-sdk-secretsmanager
5
9
  thor (~> 1.0)
6
10
 
7
11
  GEM
8
12
  remote: https://rubygems.org/
9
13
  specs:
14
+ activesupport (6.0.2.1)
15
+ concurrent-ruby (~> 1.0, >= 1.0.2)
16
+ i18n (>= 0.7, < 2)
17
+ minitest (~> 5.1)
18
+ tzinfo (~> 1.1)
19
+ zeitwerk (~> 2.2)
20
+ aws-eventstream (1.0.3)
21
+ aws-partitions (1.281.0)
22
+ aws-sdk-core (3.91.0)
23
+ aws-eventstream (~> 1.0, >= 1.0.2)
24
+ aws-partitions (~> 1, >= 1.239.0)
25
+ aws-sigv4 (~> 1.1)
26
+ jmespath (~> 1.0)
27
+ aws-sdk-ec2 (1.149.0)
28
+ aws-sdk-core (~> 3, >= 3.71.0)
29
+ aws-sigv4 (~> 1.1)
30
+ aws-sdk-secretsmanager (1.34.0)
31
+ aws-sdk-core (~> 3, >= 3.71.0)
32
+ aws-sigv4 (~> 1.1)
33
+ aws-sigv4 (1.1.1)
34
+ aws-eventstream (~> 1.0, >= 1.0.2)
35
+ concurrent-ruby (1.1.6)
10
36
  diff-lcs (1.3)
37
+ i18n (1.8.2)
38
+ concurrent-ruby (~> 1.0)
39
+ jmespath (1.4.0)
40
+ minitest (5.14.0)
11
41
  rake (12.3.3)
12
42
  rspec (3.9.0)
13
43
  rspec-core (~> 3.9.0)
@@ -23,6 +53,10 @@ GEM
23
53
  rspec-support (~> 3.9.0)
24
54
  rspec-support (3.9.2)
25
55
  thor (1.0.1)
56
+ thread_safe (0.3.6)
57
+ tzinfo (1.2.6)
58
+ thread_safe (~> 0.1)
59
+ zeitwerk (2.3.0)
26
60
 
27
61
  PLATFORMS
28
62
  ruby
@@ -27,5 +27,9 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ['lib']
29
29
 
30
+ spec.add_dependency 'activesupport'
31
+ spec.add_dependency 'aws-sdk-core'
32
+ spec.add_dependency 'aws-sdk-ec2'
33
+ spec.add_dependency 'aws-sdk-secretsmanager'
30
34
  spec.add_dependency 'thor', '~> 1.0'
31
35
  end
@@ -2,12 +2,27 @@
2
2
 
3
3
  require 'shellwords'
4
4
  require 'thor'
5
+ require 'active_support/encrypted_file'
6
+ require 'active_support/core_ext/hash/keys'
7
+ require 'aws-sdk-ec2'
8
+ require 'aws-sdk-secretsmanager'
9
+ require 'yaml'
5
10
 
11
+ require 'founders_template/utils'
12
+ require 'founders_template/config_file'
13
+
14
+ REQUIRED_SYSTEM_TOOLS = %w( direnv ).freeze
6
15
  SCRIPT_PATH = File.expand_path(File.join(__dir__, '..', '..', 'bash')).freeze
16
+ CREDENTIALS_PATH = 'config/credentials'
17
+ CREDENTIALS_KEY_FILE = File.join(CREDENTIALS_PATH, 'production.key').freeze
18
+ CONFIG_PATH = 'config'
7
19
 
8
20
  module FoundersTemplate
9
21
  class CLI < Thor
10
22
  include Thor::Actions
23
+ source_root File.join(__dir__, '../../templates')
24
+
25
+ include Utils
11
26
 
12
27
  desc 'ci SCRIPT_NAME', 'exec the ci script SCRIPT_NAME'
13
28
  def ci(script_name, *args)
@@ -17,15 +32,146 @@ module FoundersTemplate
17
32
  exec '/usr/bin/env', 'bash', file_path, *args
18
33
  end
19
34
 
20
- def self.source_root
21
- File.join(__dir__, '../../templates')
35
+ desc 'check', 'check that all the required tooling is installed'
36
+ def check
37
+ return if REQUIRED_SYSTEM_TOOLS.all? { |command| check_command(command) }
38
+
39
+ error 'Some dependencies were missing, please check the README for instructions.'
40
+ exit 1
22
41
  end
23
42
 
24
43
  desc 'install', 'install the buildspec'
25
44
  def install
45
+ check
46
+
47
+ ensure_application_config
48
+ ensure_aws_credentials
49
+ ensure_credentials_key
50
+ ensure_secret_key
51
+
26
52
  template 'buildspec.yml.erb', 'buildspec.yml'
53
+ template 'docker-compose.ci.yml.erb', 'docker-compose.ci.yml'
27
54
 
28
55
  directory 'ci', 'ci'
29
56
  end
57
+
58
+ private
59
+
60
+ def ensure_aws_credentials
61
+ return if aws_credentials?
62
+
63
+ message = <<~TEXT
64
+
65
+ We need to setup an AWS credentials profile on your system.
66
+ This will add a section to ~/.aws/credentials so you will have a profile containing
67
+ your keys for this project. This will then configure direnv so that whenever you are
68
+ inside your project's directory all AWS commands will be configured to use that
69
+ profile.
70
+
71
+ TEXT
72
+ say message, :yellow
73
+
74
+ aws_access_key_id = ask 'AWS Access Key ID:'
75
+ aws_secret_access_key = ask 'AWS Secret Access Key (typing will be hidden):', echo: false
76
+
77
+ regions = Aws::EC2::Client.new(region: 'us-east-1',
78
+ access_key_id: aws_access_key_id,
79
+ secret_access_key: aws_secret_access_key).describe_regions
80
+ aws_region = ask 'AWS Region:',
81
+ limited_to: regions.regions.map(&:region_name),
82
+ default: 'us-east-1'
83
+
84
+ add_to_envrc AWS_REGION: aws_region
85
+
86
+ profile = <<~TEXT
87
+ [#{app_config.short_name}]
88
+ aws_access_key_id = #{aws_access_key_id}
89
+ aws_secret_access_key = #{aws_secret_access_key}
90
+ TEXT
91
+ append_to_file '~/.aws/credentials', profile
92
+ add_to_envrc AWS_PROFILE: app_config.short_name
93
+ end
94
+
95
+ def secrets_manager_key_exist?(key_id)
96
+ secrets_manager.describe_secret({ secret_id: key_id })
97
+ true
98
+ rescue Aws::SecretsManager::Errors::ResourceNotFoundException
99
+ false
100
+ end
101
+
102
+ def secrets_manager_credentials_key_id
103
+ "#{app_config.short_name}/rails/production/credentials_master_key"
104
+ end
105
+
106
+ def secrets_manager_secret_key_id
107
+ "#{app_config.short_name}/rails/production/secret_key_base"
108
+ end
109
+
110
+ def ensure_credentials_key
111
+ return unless credentials_supported?
112
+ return if secrets_manager_key_exist?(secrets_manager_credentials_key_id)
113
+
114
+ ensure_credentials_key_file
115
+ copy_credentials_to_secrets_manager
116
+ end
117
+
118
+ def credentials_supported?
119
+ Dir.exist?(CREDENTIALS_PATH)
120
+ end
121
+
122
+ def ensure_credentials_key_file
123
+ return if File.exist?(CREDENTIALS_KEY_FILE)
124
+
125
+ create_file CREDENTIALS_KEY_FILE, ActiveSupport::EncryptedFile.generate_key
126
+ chmod CREDENTIALS_KEY_FILE, 0o600
127
+ end
128
+
129
+ def copy_credentials_to_secrets_manager
130
+ return if secrets_manager_key_exist?(secrets_manager_credentials_key_id)
131
+
132
+ key = run("cat #{CREDENTIALS_KEY_FILE}")
133
+ secrets_manager.create_secret(
134
+ description: "The Rails credentials key for #{app_config.short_name}",
135
+ name: secrets_manager_credentials_key_id,
136
+ secret_string: { production: key }.to_json
137
+ )
138
+ end
139
+
140
+ def ensure_secret_key
141
+ return if secrets_manager_key_exist?(secrets_manager_secret_key_id)
142
+
143
+ key = ask 'Rails Secret Key (leave blank to generate a new one):'
144
+ key = SecureRandom.hex(64) if key == ''
145
+ secrets_manager.create_secret(
146
+ description: "The Rails secret key for #{app_config.short_name}",
147
+ name: secrets_manager_secret_key_id,
148
+ secret_string: { production: key }.to_json
149
+ )
150
+ end
151
+
152
+ def secrets_manager
153
+ @secrets_manager ||= Aws::SecretsManager::Client.new
154
+ end
155
+
156
+ def aws_credentials?
157
+ sts = Aws::STS::Client.new(region: 'us-east-1')
158
+ sts.get_caller_identity
159
+ true
160
+ rescue Aws::Errors::MissingCredentialsError
161
+ false
162
+ end
163
+
164
+ def ensure_application_config
165
+ return if app_config.valid?
166
+
167
+ app_config.name = ask 'Application Name:'
168
+ app_config.short_name = ask 'Application Short Name:', default: app_config.short_name
169
+
170
+ template_file app_config
171
+ end
172
+
173
+ def app_config
174
+ @app_config ||= ConfigFile.new(CONFIG_PATH)
175
+ end
30
176
  end
31
177
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'founders_template/template_file'
4
+
5
+ module FoundersTemplate
6
+ class ConfigFile < TemplateFile
7
+ root_key 'application'
8
+ required_keys %i( name short_name )
9
+
10
+ template_file 'ft.yml.erb'
11
+ output_file 'ft.yml'
12
+
13
+ attr_accessor :name
14
+ attr_writer :short_name
15
+
16
+ def short_name
17
+ @short_name ||= name.split.map(&:chr).join.downcase
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FoundersTemplate
4
+ class TemplateFile
5
+ def self.root_key(key = nil)
6
+ @root_key = key if key
7
+ @root_key ||= nil
8
+ end
9
+
10
+ def self.output_file(file_name = nil)
11
+ @output_file = file_name if file_name
12
+ @output_file ||= nil
13
+ end
14
+
15
+ def self.template_file(file_name = nil)
16
+ @template_file = file_name if file_name
17
+ @template_file ||= nil
18
+ end
19
+
20
+ def self.required_keys(keys = nil)
21
+ @required_keys = keys if keys
22
+ @required_keys ||= []
23
+ end
24
+
25
+ def initialize(output_directory)
26
+ @output_directory = output_directory
27
+ @data = File.exist?(output_file) && YAML.load_file(output_file)
28
+ return unless @data
29
+
30
+ @data = @data[self.class.root_key] if self.class.root_key
31
+ @data.symbolize_keys!
32
+ load_data
33
+ end
34
+
35
+ def valid?
36
+ self.class.required_keys.none? { |key| public_send(key).nil? }
37
+ end
38
+
39
+ def binding_for_render
40
+ binding
41
+ end
42
+
43
+ def template_file
44
+ self.class.template_file
45
+ end
46
+
47
+ def output_file
48
+ File.join(@output_directory, self.class.output_file)
49
+ end
50
+
51
+ private
52
+
53
+ def load_data
54
+ @data.each do |key, value|
55
+ public_send("#{key}=", value)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FoundersTemplate
4
+ module Utils
5
+ def add_to_envrc(variables)
6
+ create_file '.envrc' unless File.exist?('.envrc')
7
+
8
+ variables.each do |name, value|
9
+ name = name.to_s
10
+ append_to_file '.envrc', "export #{name}=#{value}\n"
11
+ ENV[name] = value
12
+ end
13
+
14
+ run 'direnv allow .'
15
+ end
16
+
17
+ def check_command(command)
18
+ return true if system_command?(command)
19
+
20
+ say_status :missing, command
21
+ false
22
+ end
23
+
24
+ def system_command?(command)
25
+ system("which #{Shellwords.escape(command)} > /dev/null 2>&1")
26
+ end
27
+
28
+ def template_file(template_file)
29
+ template template_file.template_file,
30
+ template_file.output_file,
31
+ context: template_file.binding_for_render
32
+ end
33
+ end
34
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FoundersTemplate
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.3'
5
5
  end
@@ -1,5 +1,10 @@
1
1
  version: 0.2
2
2
 
3
+ env:
4
+ secrets-manager:
5
+ RAILS_MASTER_KEY: <%= app_config.short_name %>/rails/production/credentials_master_key:production
6
+ RAILS_SECRET_KEY: <%= app_config.short_name %>/rails/production/secret_key_base:production
7
+
3
8
  phases:
4
9
  install:
5
10
  commands:
@@ -0,0 +1,23 @@
1
+ version: '3.4'
2
+
3
+ services:
4
+ app:
5
+ image: %IMAGE
6
+ environment:
7
+ DATABASE_URL: postgres://postgres@db
8
+ REDIS_URL: redis://redis
9
+ RAILS_ENV: development
10
+ CI: 'codebuild'
11
+ CIRCLECI: 1
12
+ volumes:
13
+ - ./coverage:/app/coverage
14
+ command: puma -C config/puma.rb
15
+ depends_on:
16
+ - db
17
+ - redis
18
+ db:
19
+ image: postgres:9.6-alpine
20
+ environment:
21
+ POSTGRES_HOST_AUTH_METHOD: trust
22
+ redis:
23
+ image: redis:5.0.5-alpine
@@ -0,0 +1,5 @@
1
+ version: 1.0
2
+
3
+ application:
4
+ name: <%= name %>
5
+ short_name: <%= short_name %>
metadata CHANGED
@@ -1,15 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: founders_template
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Trae Robrock
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-12 00:00:00.000000000 Z
11
+ date: 2020-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk-core
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: aws-sdk-ec2
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: aws-sdk-secretsmanager
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
13
69
  - !ruby/object:Gem::Dependency
14
70
  name: thor
15
71
  requirement: !ruby/object:Gem::Requirement
@@ -64,11 +120,17 @@ files:
64
120
  - founders_template.gemspec
65
121
  - lib/founders_template.rb
66
122
  - lib/founders_template/cli.rb
123
+ - lib/founders_template/config_file.rb
124
+ - lib/founders_template/template_file.rb
125
+ - lib/founders_template/utils.rb
67
126
  - lib/founders_template/version.rb
127
+ - playground/config/credentials/.gitkeep
68
128
  - templates/buildspec.yml.erb
69
129
  - templates/ci/install.sh
70
130
  - templates/ci/post_build.sh
71
131
  - templates/ci/run_tests.sh
132
+ - templates/docker-compose.ci.yml.erb
133
+ - templates/ft.yml.erb
72
134
  homepage: https://github.com/trobrock/founders_template
73
135
  licenses:
74
136
  - MIT