Skip to content
This repository has been archived by the owner on Nov 19, 2018. It is now read-only.

[WIP] Brand new configuration for everything #8

Merged
merged 15 commits into from
Mar 6, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
fastlane_core (0.2.1)
fastlane_core (0.3.0)
babosa
capybara (~> 2.4.3)
colored
Expand Down Expand Up @@ -84,7 +84,7 @@ GEM
webmock (1.19.0)
addressable (>= 2.3.6)
crack (>= 0.3.2)
websocket-driver (0.5.2)
websocket-driver (0.5.3)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
xpath (2.0.0)
Expand Down
2 changes: 1 addition & 1 deletion fastlane_core.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
spec.email = ["fastlanecore@krausefx.com"]
spec.summary = %q{Contains all shared code/dependencies of the fastlane.tools}
spec.description = %q{Contains all shared code/dependencies of the fastlane.tools}
spec.homepage = "http://fastlane.tools"
spec.homepage = "https://fastlane.tools"
spec.license = "MIT"

spec.required_ruby_version = '>= 2.0.0'
Expand Down
1 change: 1 addition & 0 deletions lib/fastlane_core.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'json'
require 'fastlane_core/version'
require 'fastlane_core/helper'
require 'fastlane_core/configuration'
require 'fastlane_core/update_checker'
require 'fastlane_core/languages'
require 'fastlane_core/itunes_search_api'
Expand Down
108 changes: 108 additions & 0 deletions lib/fastlane_core/configuration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
require 'fastlane_core/configuration/config_item'
require 'fastlane_core/configuration/commander_generator'

module FastlaneCore
class Configuration
def self.create(available_options, values)
Configuration.new(available_options, values)
end

# Setting up

def initialize(available_options, values)
@available_options = available_options
@values = values

verify_input_types
verify_value_exists
verify_no_duplicates
end

def verify_input_types
raise "available_options parameter must be an array of ConfigItems".red unless @available_options.kind_of?Array
@available_options.each do |item|
raise "available_options parameter must be an array of ConfigItems".red unless item.kind_of?ConfigItem
end
raise "values parameter must be a hash".red unless @values.kind_of?Hash
end

def verify_value_exists
# Make sure the given value keys exist
@values.each do |key, value|
option = option_for_key(key)
if option
option.verify!(value) # Call the verify block for it too
else
raise "Could not find available option '#{key}' in the list of available options #{@available_options.collect { |a| a.key }}".red
end
end
end

def verify_no_duplicates
# Make sure a key was not used multiple times
@available_options.each do |current|
count = @available_options.select { |option| option.key == current.key }.count
raise "Multiple entries for configuration key '#{current.key}' found!".red if count > 1

unless current.short_option.to_s.empty?
count = @available_options.select { |option| option.short_option == current.short_option }.count
raise "Multiple entries for short_option '#{current.short_option}' found!".red if count > 1
end
end
end

# Using the class

# Returns the value for a certain key. fastlane_core tries to fetch the value from different sources
def fetch(key)
raise "Key '#{key}' must be a symbol. Example :app_id.".red unless key.kind_of?Symbol

option = option_for_key(key)
raise "Could not find option for key :#{key}. Available keys: #{@available_options.collect { |a| a.key }}".red unless option

# `if value == nil` instead of ||= because false is also a valid value

value ||= @values[key]
# TODO: configuration files
value = ENV[key.to_s] if value == nil
value = option.default_value if value == nil
value = false if (value == nil and not option.is_string) # by default boolean flags are false

while value == nil and !option.optional
value = ask("#{option.description}: ")
# Also store this value to use it from now on
begin
set(key, value)
rescue Exception => ex
puts ex
value = nil
end
end

value
end

# Overwrites or sets a new value for a given key
def set(key, value)
raise "Key '#{key}' must be a symbol. Example :app_id.".red unless key.kind_of?Symbol
option = option_for_key(key)

unless option
raise "Could not find available option '#{key}' in the list of !available options #{@available_options.collect { |a| a.key }}".red
end

option.verify!(value)

@values[key] = value
true
end

# Returns the config_item object for a given key
def option_for_key(key)
@available_options.find { |o| o.key == key }
end

# Aliases `[key]` to `fetch(key)` because Ruby can do it.
alias_method :[], :fetch
end
end
16 changes: 16 additions & 0 deletions lib/fastlane_core/configuration/commander_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
require 'commander'

module FastlaneCore
class CommanderGenerator
include Commander::Methods

def generate(options)
options.each do |option|
appendix = (option.is_string ? "STRING" : "")
type = (option.is_string ? String : nil)
short_option = option.short_option || "-#{option.key.to_s[0]}"
global_option short_option, "--#{option.key} #{appendix}", type, (option.description + " (#{option.env_name})")
end
end
end
end
69 changes: 69 additions & 0 deletions lib/fastlane_core/configuration/config_item.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
module FastlaneCore
class ConfigItem
attr_accessor :key, :env_name, :description, :short_option, :default_value, :verify_block, :is_string, :optional

# Creates a new option
# @param key (Symbol) the key which is used as command paramters or key in the fastlane tools
# @param env_name (String) the name of the environment variable, which is only used if no other values were found
# @param description (String) A description shown to the user
# @param short_option (String) A string of length 1 which is used for the command parameters (e.g. -f)
# @param default_value the value which is used if there was no given values and no environment values
# @param verify_block an optional block which is called when a new value is set.
# Check value is valid. This could be type checks or if a folder/file exists
# You have to raise a specific exception if something goes wrong. Append .red after the string
# @param is_string (String) is that parameter a string?
# @param optional (Boolean) is false by default. If set to true, also string values will not be asked to the user
def initialize(key: nil, env_name: nil, description: nil, short_option: nil, default_value: nil, verify_block: nil, is_string: true, optional: false)
raise "key must be a symbol" unless key.kind_of?Symbol
raise "env_name must be a String" unless env_name.kind_of?String
if short_option
raise "short_option must be a String of length 1" unless (short_option.kind_of?String and short_option.gsub('-', '').length == 1)
end
if description
raise "Do not let descriptions end with a '.', since it's used for user inputs as well".red if (description[-1] == '.')
end

@key = key
@env_name = env_name
@description = description
@short_option = short_option
@default_value = default_value
@verify_block = verify_block
@is_string = is_string
@optional = optional
end


# This will raise an exception if the value is not valid
def verify!(value)
raise "Invalid value '#{value}' for option '#{self}'".red unless is_valid?value
true
end

# Make sure, the value is valid (based on the verify block)
# Returns false if that's not the case
def is_valid?(value)
# we also allow nil values, which do not have to be verified.
if value
if @is_string
raise "Please pass a path as String".red unless value.kind_of?String
end

if @verify_block
begin
@verify_block.call(value)
rescue Exception => ex
Helper.log.fatal "Error setting value '#{value}' for option '#{@key}'".red
raise ex
end
end
end

true
end

def to_s
[@key, @description].join(": ")
end
end
end
2 changes: 1 addition & 1 deletion lib/fastlane_core/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module FastlaneCore
VERSION = "0.2.1"
VERSION = "0.3.0"
end
122 changes: 122 additions & 0 deletions spec/configuration_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
describe FastlaneCore do
describe FastlaneCore::Configuration do
describe "Create a new Configuration Manager" do

it "raises an error if no hash is given" do
expect {
FastlaneCore::Configuration.create([], "string")
}.to raise_error "values parameter must be a hash".red
end

it "raises an error if no array is given" do
expect {
FastlaneCore::Configuration.create("string", {})
}.to raise_error "available_options parameter must be an array of ConfigItems".red
end

it "raises an error if array contains invalid elements" do
expect {
FastlaneCore::Configuration.create(["string"], {})
}.to raise_error "available_options parameter must be an array of ConfigItems".red
end


it "raises an error if the option of a given value is not available" do
expect {
FastlaneCore::Configuration.create([], {cert_name: "value"})
}.to raise_error "Could not find available option 'cert_name' in the list of available options []".red
end

it "raises an error if a description ends with a ." do
expect {
FastlaneCore::Configuration.create([FastlaneCore::ConfigItem.new(
key: :cert_name,
env_name: "asdf",
description: "Set the profile name.")], {})
}.to raise_error "Do not let descriptions end with a '.', since it's used for user inputs as well".red
end

it "raises an error if a a key was used twice" do
expect {
FastlaneCore::Configuration.create([FastlaneCore::ConfigItem.new(
key: :cert_name,
env_name: "asdf"),
FastlaneCore::ConfigItem.new(
key: :cert_name,
env_name: "asdf")], {})
}.to raise_error "Multiple entries for configuration key 'cert_name' found!".red
end

describe "Use a valid Configuration Manager" do
before do
@options = [
FastlaneCore::ConfigItem.new(key: :cert_name,
env_name: "SIGH_PROVISIONING_PROFILE_NAME",
description: "Set the profile name",
default_value: "production_default",
verify_block: nil),
FastlaneCore::ConfigItem.new(key: :output,
env_name: "SIGH_OUTPUT_PATH",
description: "Directory in which the profile should be stored",
default_value: ".",
verify_block: Proc.new do |value|
raise "Could not find output directory '#{value}'".red unless File.exists?(value)
end)
]
@values = {
cert_name: "asdf",
output: ".."
}
@config = FastlaneCore::Configuration.create(@options, @values)
end

describe "fetch" do
it "raises an error if a non symbol was given" do
expect {
@config.fetch(123)
}.to raise_error "Key '123' must be a symbol. Example :app_id.".red
end

it "raises an error if this option does not exist" do
expect {
@config[:asdfasdf]
}.to raise_error "Could not find option for key :asdfasdf. Available keys: [:cert_name, :output]".red
end

it "returns the value for the given key if given" do
expect(@config.fetch(:cert_name)).to eq(@values[:cert_name])
end

it "returns the value for the given key if given using []" do
expect(@config[:cert_name]).to eq(@values[:cert_name])
end

it "returns the default value if nothing else was given" do
@config.set(:cert_name, nil)
expect(@config[:cert_name]).to eq("production_default")
end
end

describe "verify_block" do
it "throws an error if the key doesn't exist" do
expect {
@config.set(:non_existing, "value")
}.to raise_error("Could not find available option 'non_existing' in the list of !available options [:cert_name, :output]".red)
end

it "throws an error if it's invalid" do
expect {
@config.set(:output, 132)
}.to raise_error("Please pass a path as String".red)
end

it "allows valid updates" do
new_val = "../../"
expect(@config.set(:output, new_val)).to eq(true)
expect(@config[:output]).to eq(new_val)
end
end
end
end
end
end