founders_template 0.1.2 → 0.1.3

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
  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