exercism-config 0.33.0
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 +7 -0
- data/.github/config/rubocop_linter_action.yml +12 -0
- data/.github/workflows/rubocop.yml +28 -0
- data/.github/workflows/tests.yml +80 -0
- data/.gitignore +12 -0
- data/.rubocop.yml +81 -0
- data/.ruby-version +1 -0
- data/Gemfile +12 -0
- data/LICENSE +661 -0
- data/README.md +26 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/release +3 -0
- data/bin/rubocop-quick +4 -0
- data/bin/setup_exercism_config +84 -0
- data/bin/setup_exercism_local_aws +97 -0
- data/exercism_config.gemspec +41 -0
- data/lib/exercism/config.rb +12 -0
- data/lib/exercism_config.rb +27 -0
- data/lib/exercism_config/determine_environment.rb +16 -0
- data/lib/exercism_config/generate_aws_settings.rb +38 -0
- data/lib/exercism_config/retrieve.rb +67 -0
- data/lib/exercism_config/setup_dynamodb_client.rb +31 -0
- data/lib/exercism_config/setup_s3_client.rb +32 -0
- data/lib/exercism_config/version.rb +3 -0
- data/package.json +12 -0
- data/settings/development.yml +8 -0
- data/settings/docker.yml +8 -0
- data/settings/test-ci.yml +9 -0
- data/settings/test-docker.yml +9 -0
- data/settings/test-local.yml +9 -0
- data/yarn.lock +527 -0
- metadata +189 -0
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Exercism Config
|
2
|
+
|
3
|
+

|
4
|
+
[](https://codeclimate.com/github/exercism/config/maintainability)
|
5
|
+
[](https://codeclimate.com/github/exercism/config/test_coverage)
|
6
|
+
[](https://badge.fury.io/rb/exercism_config)
|
7
|
+
|
8
|
+
When terraform creates Exercism's infrastructure, it writes endpoints and DNS entries to DynamoDB.
|
9
|
+
This gem allows you to trivially retrieve that data.
|
10
|
+
|
11
|
+
When running on AWS, simply ensure the machine has read-access to the relevant table (currently hardcoded to `config`).
|
12
|
+
On a local machine specify the AWS_PROFILE environment variable with the relevant profile stored in your `.aws/credentials`.
|
13
|
+
|
14
|
+
## Usage
|
15
|
+
|
16
|
+
Simply include this gem in your Gemfile, require it, and then refer to the object:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
# Gemfile
|
20
|
+
gem 'exercism_config'
|
21
|
+
|
22
|
+
# Your code
|
23
|
+
require 'exercism_config'
|
24
|
+
ExercismConfig.config.webservers_alb_dns_name
|
25
|
+
```
|
26
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'exercism_config'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require 'irb'
|
14
|
+
IRB.start(__FILE__)
|
data/bin/release
ADDED
data/bin/rubocop-quick
ADDED
@@ -0,0 +1,4 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
git diff --name-status --staged | grep '^[MA]' | grep -o '\\s\\+.*rb' | xargs bundle exec rubocop --except Metrics --auto-correct --format quiet --force-exclusion lib/exercism_config.rb && \
|
4
|
+
git diff --name-status --staged | grep '^[MA]' | grep -o '\\s\\+.*rb' | xargs git add
|
@@ -0,0 +1,84 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'exercism_config'
|
5
|
+
require 'erb'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
env = ExercismConfig::DetermineEnvironment.call
|
9
|
+
if env == :production
|
10
|
+
puts 'Aborted! This script should not be run in production.'
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_table(client)
|
15
|
+
client.create_table(
|
16
|
+
table_name: :config,
|
17
|
+
attribute_definitions: [
|
18
|
+
{
|
19
|
+
attribute_name: 'id',
|
20
|
+
attribute_type: 'S'
|
21
|
+
}
|
22
|
+
],
|
23
|
+
key_schema: [
|
24
|
+
{
|
25
|
+
attribute_name: 'id',
|
26
|
+
key_type: 'HASH'
|
27
|
+
}
|
28
|
+
],
|
29
|
+
provisioned_throughput: {
|
30
|
+
read_capacity_units: 1,
|
31
|
+
write_capacity_units: 1
|
32
|
+
}
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete_table(client)
|
37
|
+
client.delete_table(
|
38
|
+
table_name: :config
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_config_value(client, id, value)
|
43
|
+
client.put_item(
|
44
|
+
table_name: :config,
|
45
|
+
item: {
|
46
|
+
id: id,
|
47
|
+
value: value
|
48
|
+
}
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
client = ExercismConfig::SetupDynamoDBClient.call
|
53
|
+
|
54
|
+
begin
|
55
|
+
create_table(client)
|
56
|
+
rescue Aws::DynamoDB::Errors::ResourceInUseException => e
|
57
|
+
if ARGV.include?('--force')
|
58
|
+
puts 'Table exists. Recreating...'
|
59
|
+
delete_table(client)
|
60
|
+
create_table(client)
|
61
|
+
puts 'Table recreated.'
|
62
|
+
else
|
63
|
+
puts 'Table exists. Not recreating.'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
settings_file_arg = ARGV.select { |arg| arg.start_with?('--settings-file=') }.first
|
68
|
+
settings_file =
|
69
|
+
if settings_file_arg
|
70
|
+
settings_file_arg.split('=').last
|
71
|
+
elsif ENV['EXERCISM_DOCKER']
|
72
|
+
File.expand_path('../settings/docker.yml', __dir__)
|
73
|
+
elsif ENV['EXERCISM_CI']
|
74
|
+
File.expand_path('../settings/test-ci.yml', __dir__)
|
75
|
+
else
|
76
|
+
File.expand_path('../settings/development.yml', __dir__)
|
77
|
+
end
|
78
|
+
|
79
|
+
puts "Using settings file: #{settings_file}"
|
80
|
+
settings = YAML.load(ERB.new(File.read(settings_file)).result)
|
81
|
+
|
82
|
+
settings.each do |key, value|
|
83
|
+
set_config_value(client, key, value)
|
84
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "bundler/setup"
|
3
|
+
require "exercism_config"
|
4
|
+
|
5
|
+
# Only allow this to run in development
|
6
|
+
return unless Exercism.environment == :development
|
7
|
+
|
8
|
+
puts "Create AWS/DynamoDB tables..."
|
9
|
+
|
10
|
+
Exercism.config.dynamodb_client = ExercismConfig::SetupDynamoDBClient.()
|
11
|
+
|
12
|
+
##################
|
13
|
+
# Setup local s3 #
|
14
|
+
##################
|
15
|
+
|
16
|
+
# We don't need this running for CI atm as none of our
|
17
|
+
# tests actually hit s3. Although we might choose to change this
|
18
|
+
unless ENV["EXERCISM_CI"]
|
19
|
+
begin
|
20
|
+
ExercismConfig::SetupS3Client.().create_bucket(bucket: Exercism.config.aws_iterations_bucket)
|
21
|
+
rescue Seahorse::Client::NetworkingError => e
|
22
|
+
puts "local S3 not up yet..."
|
23
|
+
sleep 2 # slighty retry delaty
|
24
|
+
retry
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
########################
|
29
|
+
# Setup local dynamodb #
|
30
|
+
########################
|
31
|
+
%w[tooling_jobs tooling_jobs-test].each do |table_name|
|
32
|
+
begin
|
33
|
+
Exercism.config.dynamodb_client.delete_table(
|
34
|
+
table_name: table_name
|
35
|
+
)
|
36
|
+
rescue Aws::DynamoDB::Errors::ResourceNotFoundException
|
37
|
+
end
|
38
|
+
puts "[x] #{table_name}"
|
39
|
+
|
40
|
+
Exercism.config.dynamodb_client.create_table(
|
41
|
+
table_name: table_name,
|
42
|
+
attribute_definitions: [
|
43
|
+
{
|
44
|
+
attribute_name: "id",
|
45
|
+
attribute_type: "S"
|
46
|
+
}
|
47
|
+
],
|
48
|
+
key_schema: [
|
49
|
+
{
|
50
|
+
attribute_name: "id",
|
51
|
+
key_type: "HASH"
|
52
|
+
}
|
53
|
+
],
|
54
|
+
provisioned_throughput: {
|
55
|
+
read_capacity_units: 1,
|
56
|
+
write_capacity_units: 1
|
57
|
+
}
|
58
|
+
)
|
59
|
+
|
60
|
+
Exercism.config.dynamodb_client.update_table(
|
61
|
+
table_name: table_name,
|
62
|
+
attribute_definitions: [
|
63
|
+
{
|
64
|
+
attribute_name: "job_status",
|
65
|
+
attribute_type: "S"
|
66
|
+
},
|
67
|
+
{
|
68
|
+
attribute_name: "created_at",
|
69
|
+
attribute_type: "N"
|
70
|
+
}
|
71
|
+
],
|
72
|
+
global_secondary_index_updates: [
|
73
|
+
{
|
74
|
+
create: {
|
75
|
+
index_name: "job_status", # required
|
76
|
+
key_schema: [ # required
|
77
|
+
{
|
78
|
+
attribute_name: "job_status", # required
|
79
|
+
key_type: "HASH" # required, accepts HASH, RANGE
|
80
|
+
},
|
81
|
+
{
|
82
|
+
attribute_name: "created_at", # required
|
83
|
+
key_type: "RANGE" # required, accepts HASH, RANGE
|
84
|
+
}
|
85
|
+
],
|
86
|
+
projection: { # required
|
87
|
+
projection_type: "KEYS_ONLY"
|
88
|
+
},
|
89
|
+
provisioned_throughput: {
|
90
|
+
read_capacity_units: 1, # required
|
91
|
+
write_capacity_units: 1 # required
|
92
|
+
}
|
93
|
+
}
|
94
|
+
}
|
95
|
+
]
|
96
|
+
)
|
97
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative 'lib/exercism_config/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'exercism-config'
|
5
|
+
spec.version = ExercismConfig::VERSION
|
6
|
+
spec.authors = ['Jeremy Walker']
|
7
|
+
spec.email = ['jez.walker@gmail.com']
|
8
|
+
|
9
|
+
spec.summary = 'Retrieves stored config for Exercism'
|
10
|
+
spec.homepage = 'https://exercism.io'
|
11
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
|
12
|
+
|
13
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
14
|
+
spec.metadata['source_code_uri'] = 'https://github.com/exercism/config'
|
15
|
+
|
16
|
+
# Specify which files should be added to the gem when it is released.
|
17
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
18
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
19
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
20
|
+
end
|
21
|
+
spec.bindir = "bin"
|
22
|
+
spec.executables = %w[
|
23
|
+
setup_exercism_config
|
24
|
+
setup_exercism_local_aws
|
25
|
+
]
|
26
|
+
spec.require_paths = ["lib"]
|
27
|
+
|
28
|
+
spec.add_dependency 'aws-sdk-dynamodb', '~> 1.0'
|
29
|
+
spec.add_dependency 'mandate'
|
30
|
+
spec.add_dependency 'zeitwerk'
|
31
|
+
|
32
|
+
spec.add_development_dependency 'bundler', '~> 2.1'
|
33
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
34
|
+
spec.add_development_dependency 'mocha'
|
35
|
+
spec.add_development_dependency 'rake', '~> 12.3'
|
36
|
+
|
37
|
+
# This isn't a compulsary dependency
|
38
|
+
# but can be used if someone puts it in their
|
39
|
+
# own gemfile
|
40
|
+
spec.add_development_dependency 'aws-sdk-s3'
|
41
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'aws-sdk-dynamodb'
|
2
|
+
require 'mandate'
|
3
|
+
require 'ostruct'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
require_relative 'exercism_config/determine_environment'
|
7
|
+
require_relative 'exercism_config/generate_aws_settings'
|
8
|
+
require_relative 'exercism_config/setup_dynamodb_client'
|
9
|
+
require_relative 'exercism_config/setup_s3_client'
|
10
|
+
require_relative 'exercism_config/retrieve'
|
11
|
+
require_relative 'exercism_config/generate_aws_settings'
|
12
|
+
require_relative 'exercism_config/version'
|
13
|
+
|
14
|
+
require_relative 'exercism/config'
|
15
|
+
|
16
|
+
module Exercism
|
17
|
+
class ConfigError < RuntimeError
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.environment
|
21
|
+
@environment ||= ExercismConfig::DetermineEnvironment.()
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.config
|
25
|
+
@config ||= ExercismConfig::Retrieve.()
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ExercismConfig
|
2
|
+
class DetermineEnvironment
|
3
|
+
include Mandate
|
4
|
+
|
5
|
+
def call
|
6
|
+
env = ENV['EXERCISM_ENV'] || ENV['RAILS_ENV'] || ENV['APP_ENV']
|
7
|
+
raise Exercism::ConfigError, 'No environment set - set one of EXERCISM_ENV, RAILS_ENV or APP_ENV' unless env
|
8
|
+
|
9
|
+
unless %w[development test production].include?(env)
|
10
|
+
raise Exercism::ConfigError, "environment must be one of development, test or production. Got #{env}."
|
11
|
+
end
|
12
|
+
|
13
|
+
env.to_sym
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module ExercismConfig
|
2
|
+
class GenerateAwsSettings
|
3
|
+
include Mandate
|
4
|
+
|
5
|
+
def call
|
6
|
+
{
|
7
|
+
region: 'eu-west-2',
|
8
|
+
profile: profile,
|
9
|
+
access_key_id: aws_access_key_id,
|
10
|
+
secret_access_key: aws_secret_access_key
|
11
|
+
}.select { |_k, v| v }
|
12
|
+
end
|
13
|
+
|
14
|
+
memoize
|
15
|
+
def aws_access_key_id
|
16
|
+
case Exercism.environment
|
17
|
+
when :development, :test
|
18
|
+
'FAKE'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
memoize
|
23
|
+
def aws_secret_access_key
|
24
|
+
case Exercism.environment
|
25
|
+
when :development, :test
|
26
|
+
'FAKE'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
memoize
|
31
|
+
def profile
|
32
|
+
case Exercism.environment
|
33
|
+
when :production
|
34
|
+
'exercism_staging'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ExercismConfig
|
2
|
+
class Retrieve
|
3
|
+
include Mandate
|
4
|
+
|
5
|
+
def call
|
6
|
+
return generate_mock if Exercism.environment == :test
|
7
|
+
|
8
|
+
retrieve_from_dynamodb
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def generate_mock
|
13
|
+
require 'erb'
|
14
|
+
require 'yaml'
|
15
|
+
|
16
|
+
filename = if ENV["EXERCISM_CI"]
|
17
|
+
'test-ci'
|
18
|
+
elsif ENV["EXERCISM_DOCKER"]
|
19
|
+
'test-docker'
|
20
|
+
else
|
21
|
+
'test-local'
|
22
|
+
end
|
23
|
+
|
24
|
+
settings_file = File.expand_path("../../../settings/#{filename}.yml", __FILE__)
|
25
|
+
settings = YAML.safe_load(ERB.new(File.read(settings_file)).result)
|
26
|
+
|
27
|
+
Exercism::Config.new(settings, {})
|
28
|
+
end
|
29
|
+
|
30
|
+
def retrieve_from_dynamodb
|
31
|
+
client = SetupDynamoDBClient.()
|
32
|
+
|
33
|
+
resp = client.scan({ table_name: 'config' })
|
34
|
+
items = resp.to_h[:items]
|
35
|
+
data = items.each_with_object({}) do |item, h|
|
36
|
+
h[item['id']] = item['value']
|
37
|
+
end
|
38
|
+
|
39
|
+
# Tweak things for dynamodb when we're running in test mode
|
40
|
+
if Exercism.environment == :test
|
41
|
+
%w[dynamodb_tooling_jobs_table].each do |key|
|
42
|
+
data[key] = "#{data[key]}-test"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
aws_settings = GenerateAwsSettings.()
|
47
|
+
Exercism::Config.new(data, aws_settings)
|
48
|
+
rescue Exercism::ConfigError
|
49
|
+
raise
|
50
|
+
rescue StandardError => e
|
51
|
+
raise Exercism::ConfigError, "Exercism Config could not be loaded: #{e.message}"
|
52
|
+
end
|
53
|
+
|
54
|
+
memoize
|
55
|
+
def aws_client
|
56
|
+
config = {
|
57
|
+
region: 'eu-west-2',
|
58
|
+
profile: profile,
|
59
|
+
endpoint: endpoint,
|
60
|
+
access_key_id: aws_access_key_id,
|
61
|
+
secret_access_key: aws_secret_access_key
|
62
|
+
}.select { |_k, v| v }
|
63
|
+
|
64
|
+
Aws::DynamoDB::Client.new(config)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|