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 +4 -4
- data/.gitignore +1 -0
- data/Gemfile-rails6.lock +35 -1
- data/founders_template.gemspec +4 -0
- data/lib/founders_template/cli.rb +148 -2
- data/lib/founders_template/config_file.rb +20 -0
- data/lib/founders_template/template_file.rb +59 -0
- data/lib/founders_template/utils.rb +34 -0
- data/lib/founders_template/version.rb +1 -1
- data/templates/buildspec.yml.erb +5 -0
- data/templates/docker-compose.ci.yml.erb +23 -0
- data/templates/ft.yml.erb +5 -0
- metadata +64 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f778c67aa0b23fdf70d7ee41b7e989a774e7a810ada15d2f805ddf47785aec5
|
4
|
+
data.tar.gz: b27060bdfec354a751932afb8ba2fed4252162cef4ea4fa1e507e7ff8b8ea841
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5ea28ed9b81d17c257a3202b801fe86e25a625cd9b2a3fd756c7334bbded7c1aef7aecaeae0703046d6ea216634cf4dc25cc2da6de4f37f52c8c5826449bde4
|
7
|
+
data.tar.gz: 88515689c9a372a5aa3cdd38e971ecf4b22b2a1300bb2c47600695d86c1631d4e099915382df9d20150afc8a408564d85c57e1b6bb6de3349ea42c4d4650bd14
|
data/.gitignore
CHANGED
data/Gemfile-rails6.lock
CHANGED
@@ -1,13 +1,43 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
founders_template (0.1.
|
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
|
data/founders_template.gemspec
CHANGED
@@ -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
|
-
|
21
|
-
|
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
|
data/templates/buildspec.yml.erb
CHANGED
@@ -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
|
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.
|
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-
|
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
|