addons 0.0.9 → 0.1.0

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
  SHA1:
3
- metadata.gz: 34d47952c09b18520a6a613dd4f73f73548f924d
4
- data.tar.gz: 91f7fd89e92b1eb2c77e70106cc4911dbf944af2
3
+ metadata.gz: 4b1f48899f1dcbaf1336913a3e4212ee1221bf0a
4
+ data.tar.gz: 6761392fc427226f1466592bf4942effee8b3c5e
5
5
  SHA512:
6
- metadata.gz: 9130ec44b10b49d157ef9137ebd3bb62a3eb20b7a07d8938c802e7cc3d5d7d8ef246152a2f33ac3ff1ac30cebbcdcc38e9d0c0d1e16f4278c1c568779a667fda
7
- data.tar.gz: bb1412197ba4e31355364b844fb351367c4176561fef8523db7b24f467148ead25e62ecdcaae36acbdce98458a4c1872b42938c80ab6881c117f76def7cafa05
6
+ metadata.gz: 2d6ec04265ee6c58aea869d1f88a365079deb94fd68efa7c01bb4b1513eb7962f57955007003fa0dc9cf4f42e132407248ac6fed2193b425ee1518bd8d5d231e
7
+ data.tar.gz: 7f27557fc9550412a72917aa0ed1631e45ae50e7b2a88709e663a382291e4675da5c27a59b6872887697623f48daa33b04cace039ad5e565d77d20b9a823141e
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in addons.gemspec
4
4
  gemspec
5
+
6
+ gem 'rest_client'
7
+ gem 'json'
8
+ gem 'rails'
data/Gemfile.lock CHANGED
@@ -1,39 +1,38 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- addons (0.0.5)
5
- figaro
4
+ addons (0.1.0)
6
5
  json
7
6
 
8
7
  GEM
9
8
  remote: https://rubygems.org/
10
9
  specs:
11
- actionmailer (4.0.1)
12
- actionpack (= 4.0.1)
10
+ actionmailer (4.0.3)
11
+ actionpack (= 4.0.3)
13
12
  mail (~> 2.5.4)
14
- actionpack (4.0.1)
15
- activesupport (= 4.0.1)
13
+ actionpack (4.0.3)
14
+ activesupport (= 4.0.3)
16
15
  builder (~> 3.1.0)
17
16
  erubis (~> 2.7.0)
18
17
  rack (~> 1.5.2)
19
18
  rack-test (~> 0.6.2)
20
- activemodel (4.0.1)
21
- activesupport (= 4.0.1)
19
+ activemodel (4.0.3)
20
+ activesupport (= 4.0.3)
22
21
  builder (~> 3.1.0)
23
- activerecord (4.0.1)
24
- activemodel (= 4.0.1)
22
+ activerecord (4.0.3)
23
+ activemodel (= 4.0.3)
25
24
  activerecord-deprecated_finders (~> 1.0.2)
26
- activesupport (= 4.0.1)
25
+ activesupport (= 4.0.3)
27
26
  arel (~> 4.0.0)
28
27
  activerecord-deprecated_finders (1.0.3)
29
- activesupport (4.0.1)
28
+ activesupport (4.0.3)
30
29
  i18n (~> 0.6, >= 0.6.4)
31
30
  minitest (~> 4.2)
32
31
  multi_json (~> 1.3)
33
32
  thread_safe (~> 0.1)
34
33
  tzinfo (~> 0.3.37)
35
34
  arel (4.0.2)
36
- atomic (1.1.14)
35
+ atomic (1.1.16)
37
36
  builder (3.1.4)
38
37
  diff-lcs (1.2.5)
39
38
  erubis (2.7.0)
@@ -48,25 +47,28 @@ GEM
48
47
  treetop (~> 1.4.8)
49
48
  mime-types (1.25.1)
50
49
  minitest (4.7.5)
51
- multi_json (1.8.4)
52
- polyglot (0.3.3)
50
+ multi_json (1.9.2)
51
+ netrc (0.7.7)
52
+ polyglot (0.3.4)
53
53
  rack (1.5.2)
54
54
  rack-test (0.6.2)
55
55
  rack (>= 1.0)
56
- rails (4.0.1)
57
- actionmailer (= 4.0.1)
58
- actionpack (= 4.0.1)
59
- activerecord (= 4.0.1)
60
- activesupport (= 4.0.1)
56
+ rails (4.0.3)
57
+ actionmailer (= 4.0.3)
58
+ actionpack (= 4.0.3)
59
+ activerecord (= 4.0.3)
60
+ activesupport (= 4.0.3)
61
61
  bundler (>= 1.3.0, < 2.0)
62
- railties (= 4.0.1)
62
+ railties (= 4.0.3)
63
63
  sprockets-rails (~> 2.0.0)
64
- railties (4.0.1)
65
- actionpack (= 4.0.1)
66
- activesupport (= 4.0.1)
64
+ railties (4.0.3)
65
+ actionpack (= 4.0.3)
66
+ activesupport (= 4.0.3)
67
67
  rake (>= 0.8.7)
68
68
  thor (>= 0.18.1, < 2.0)
69
69
  rake (10.1.1)
70
+ rest_client (1.7.2)
71
+ netrc (~> 0.7.7)
70
72
  rspec (2.14.1)
71
73
  rspec-core (~> 2.14.0)
72
74
  rspec-expectations (~> 2.14.0)
@@ -75,7 +77,7 @@ GEM
75
77
  rspec-expectations (2.14.5)
76
78
  diff-lcs (>= 1.1.3, < 2.0)
77
79
  rspec-mocks (2.14.5)
78
- sprockets (2.10.1)
80
+ sprockets (2.11.0)
79
81
  hike (~> 1.2)
80
82
  multi_json (~> 1.0)
81
83
  rack (~> 1.0)
@@ -85,13 +87,13 @@ GEM
85
87
  activesupport (>= 3.0)
86
88
  sprockets (~> 2.8)
87
89
  thor (0.18.1)
88
- thread_safe (0.1.3)
89
- atomic
90
+ thread_safe (0.3.1)
91
+ atomic (>= 1.1.7, < 2)
90
92
  tilt (1.4.1)
91
93
  treetop (1.4.15)
92
94
  polyglot
93
95
  polyglot (>= 0.3.1)
94
- tzinfo (0.3.38)
96
+ tzinfo (0.3.39)
95
97
 
96
98
  PLATFORMS
97
99
  ruby
@@ -99,5 +101,9 @@ PLATFORMS
99
101
  DEPENDENCIES
100
102
  addons!
101
103
  bundler (~> 1.3)
104
+ figaro
105
+ json
106
+ rails
102
107
  rake
108
+ rest_client
103
109
  rspec (~> 2.6)
data/README.md CHANGED
@@ -16,9 +16,55 @@ Or install it yourself as:
16
16
 
17
17
  $ gem install addons
18
18
 
19
- ## Usage
19
+ ## Recipe Runner
20
+
21
+ To run all recipes related to your app, run this in your Terminal:
22
+ ```shell
23
+ rake addons:recipe:run[all]
24
+ ```
25
+
26
+ ### Recipes
27
+
28
+ #### Mailgun SMTP
29
+
30
+ Run the recipe
31
+ ```shell
32
+ rake addons:recipe:run[mailgun_smtp]
33
+ ```
34
+
35
+ Copy and paste this to the rails console to test your email settings
36
+ ```ruby
37
+ class TestMailer < ActionMailer::Base
38
+
39
+ default :from => "info@addonlist.com"
40
+
41
+ def welcome_email
42
+ mail(:to => "youremail@example.com", :subject => "Test Mailgun SMTP mail", :body => "Test Mailgun SMTP mail body")
43
+ end
44
+ end
45
+
46
+ TestMailer.welcome_email.deliver
47
+ ```
48
+
49
+ #### Mailgun HTTP
50
+
51
+ Run the recipe
52
+ ```shell
53
+ rake addons:recipe:run[mailgun_http]
54
+ ```
55
+
56
+ Copy and paste this to the rails console to test your email settings
57
+ ```ruby
58
+ email = {
59
+ to: "youremail@example.com",
60
+ from: "info@addonlist.com",
61
+ subject: "Test Mailgun HTTP mail",
62
+ body: "Test Mailgun HTTP mail body"
63
+ }
64
+
65
+ Addons::Mailgun.send_simple_message(email)
66
+ ```
20
67
 
21
- TODO: Write usage instructions here
22
68
 
23
69
  ## Contributing
24
70
 
data/addons.gemspec CHANGED
@@ -18,9 +18,11 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency "rest_client"
21
22
  spec.add_dependency "json"
22
23
  spec.add_dependency "figaro"
23
24
 
25
+ spec.add_development_dependency "rails"
24
26
  spec.add_development_dependency "bundler", "~> 1.3"
25
27
  spec.add_development_dependency "rake"
26
28
  spec.add_development_dependency "rspec", "~> 2.6"
data/lib/addons.rb CHANGED
@@ -2,5 +2,5 @@ require "addons/version"
2
2
  require "addons/config"
3
3
 
4
4
  module Addons
5
- # Your code goes here...
5
+ require "addons/railtie" if defined?(Rails)
6
6
  end
data/lib/addons/config.rb CHANGED
@@ -2,7 +2,7 @@ require 'net/http'
2
2
  require 'open-uri'
3
3
  require 'json'
4
4
 
5
- BASE_CONFIG_URL = "https://launchbox.herokuapp.com/api/v1/apps/config"
5
+ BASE_CONFIG_URL = "https://launchpack.io/api/v1/apps/config"
6
6
 
7
7
  module Addons
8
8
  class Config
@@ -44,23 +44,6 @@ module Addons
44
44
 
45
45
  services = JSON.parse(response)
46
46
 
47
- # gitignore config/application.yml so we aren't storing sensitive info in .git
48
- # TODO: replace figaro with figaro-addons and application.yml with addons.yml
49
- gitignore = Rails.root.join('.gitignore')
50
- if File.readlines(gitignore).grep(/config\/application.yml/).size == 0
51
- File.open(gitignore, 'a') do |file|
52
- file.puts 'config/application.yml'
53
- end
54
- end
55
-
56
- figaro = Rails.root.join('Gemfile')
57
- if File.readlines(figaro).grep(/gem 'figaro'/).size == 0
58
- File.open(figaro, 'a') do |file|
59
- file.puts ""
60
- file.puts "gem 'figaro' # Addons dependency"
61
- end
62
- end
63
-
64
47
  # write config/application.yml to load env vars on startup
65
48
  filename = Rails.root.join('config', 'application.yml')
66
49
 
@@ -0,0 +1,10 @@
1
+ require 'addons'
2
+ require 'rails'
3
+
4
+ module Addons
5
+ class Railtie < Rails::Railtie
6
+ rake_tasks do
7
+ load "tasks/addons_recipe.rake"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,133 @@
1
+ module Addons
2
+ module Recipe
3
+ module Instructions
4
+ class Git
5
+ GIT_EXISTS = {
6
+ "run_msg" => "Verifying you're running this recipe in the top level of a Git repository.",
7
+ "type" => InstructionTypes::DIRECTORY_EXISTS,
8
+ "command" => "./.git",
9
+ "error_msg" => "Error: This is not the top level of a git repository. Must exit.",
10
+ }
11
+ GIT_ALL_CODE_COMMITTED = {
12
+ "run_msg" => "Verifying that you have no uncommitted code in Git",
13
+ "type" => InstructionTypes::TERMINAL_COMMAND,
14
+ "command" => "git status",
15
+ "expected_result" => {
16
+ "type" => ResultTypes::DOES_NOT_CONTAIN_STRING,
17
+ "values" => ["Changes not staged for commit", "Changes to be committed"]
18
+ },
19
+ "error_msg" => "Error: You have unstaged files or uncommitted changes in Git. Please commit or stash everything so we can start on a clean slate.",
20
+ }
21
+ GIT_COMMIT_RECIPE = {
22
+ "run_msg" => "Committing changes made by #{Addons::Recipe::RECIPE_NAME_PLACEHOLDER} version: #{Addons::Recipe::RECIPE_VERSION_PLACEHOLDER} Launchpack.io recipe",
23
+ "type" => InstructionTypes::TERMINAL_COMMAND,
24
+ "command" => "git add .; git commit -m \"LAUNCHPACK RECIPE - #{Addons::Recipe::RECIPE_NAME_PLACEHOLDER} version: #{Addons::Recipe::RECIPE_VERSION_PLACEHOLDER}\"",
25
+ "expected_result" => {
26
+ "type" => ResultTypes::NO_EXPECTATION
27
+ },
28
+ "error_msg" => "Error: Git commit for this recipe failed.",
29
+ }
30
+ GIT_RESET_HARD_HEAD = {
31
+ "run_msg" => "There was an error, so we're undoing our changes. If you cannot fix this based on the error message, contact support@addonlist.com.",
32
+ "type" => InstructionTypes::TERMINAL_COMMAND,
33
+ "command" => "git add .; git reset --hard HEAD",
34
+ "expected_result" => {
35
+ "type" => ResultTypes::DOES_NOT_CONTAIN_STRING,
36
+ "values" => ["HEAD is now at"]
37
+ },
38
+ "error_msg" => "Error: we could not reset our work in Git. We hope we cleaned up this recipe, but can't be sure."
39
+ }
40
+ end # class Git
41
+
42
+ class Rails
43
+ RAILS_INITIALIZERS_EXIST = {
44
+ "run_msg" => "Verifying you have a config/initializers directory, per Rails 4",
45
+ "type" => InstructionTypes::DIRECTORY_EXISTS,
46
+ "command" => "./config/initializers",
47
+ "error_msg" => "Error: This does not look like the Rails directory: config/initializers not found"
48
+ }
49
+ RAILS_INITIALIZERS_ADDONS_DIR = {
50
+ "run_msg" => "Creating config/initializers/addons directory",
51
+ "type" => InstructionTypes::DIRECTORY_CREATE,
52
+ "command" => "./config/initializers/addons",
53
+ "error_msg" => "Error: Could not create ./config/initializers/addons directory"
54
+ }
55
+ end # class Rails
56
+
57
+ class Bundler
58
+ BUNDLER_INSTALL = {
59
+ "run_msg" => "running bundle install",
60
+ "type" => InstructionTypes::TERMINAL_COMMAND,
61
+ "command" => "bundle install",
62
+ "expected_result" => {
63
+ "type" => ResultTypes::NO_EXPECTATION
64
+ },
65
+ "error_msg" => "Error: You have unstaged files or uncommitted changes in Git. Please commit or stash everything so we can start on a clean slate."
66
+ }
67
+ end # class Bundler
68
+
69
+ class Addons
70
+ ADDON_RECIPES_INSTALLED_EXISTS = {
71
+ "run_msg" => "Checking for your ./addon_recipes_installed.yml file",
72
+ "type" => InstructionTypes::TERMINAL_COMMAND,
73
+ "command" => "touch ./addon_recipes_installed.yml",
74
+ "expected_result" => {
75
+ "type" => ResultTypes::NO_EXPECTATION
76
+ },
77
+ "error_msg" => "Error: Problem creating addon_recipes_installed.yml to record your installed recipes"
78
+ }
79
+ RECIPE_HASNT_BEEN_RUN_BEFORE = {
80
+ "run_msg" => "Verifying you have not installed this recipe before",
81
+ "type" => InstructionTypes::TERMINAL_COMMAND,
82
+ "command" => "grep '<RECIPE_HANDLE_PLACEHOLDER>' ./addon_recipes_installed.yml",
83
+ "expected_result" => {
84
+ "type" => ResultTypes::IS_EXACT_STRING,
85
+ "values" => [""]
86
+ },
87
+ "error_msg" => "Error: This recipe (<RECIPE_NAME_PLACEHOLDER>) has been run before. It cannot be run again."
88
+ }
89
+ RECORD_RECIPE_INSTALLED = {
90
+ "run_msg" => "Adding \"<RECIPE_HANDLE_PLACEHOLDER>: '<RECIPE_VERSION_PLACEHOLDER>'\" to ./addon_recipes_installed.yml",
91
+ "type" => InstructionTypes::MODIFY_CODE,
92
+ "command" => {
93
+ "type" => ModifyCodeTypes::ADD_CODE_WITHOUT_TAGS,
94
+ "file" => "./addon_recipes_installed.yml",
95
+ "code" => "<RECIPE_HANDLE_PLACEHOLDER>: '<RECIPE_VERSION_PLACEHOLDER>'",
96
+ },
97
+ "error_msg" => "Error: Could not record recipe installation in ./addon_recipes_installed.yml"
98
+ }
99
+ end
100
+
101
+ end # module Instructions
102
+
103
+ class Commons
104
+ GIT_READY_RECIPE = [
105
+ # makes sure user has .git
106
+ Addons::Recipe::Instructions::Git::GIT_EXISTS,
107
+ # make sure no uncommitted code
108
+ Addons::Recipe::Instructions::Git::GIT_ALL_CODE_COMMITTED,
109
+ ]
110
+
111
+ START_RECIPE = [
112
+ # verify config/initializers directory
113
+ Addons::Recipe::Instructions::Rails::RAILS_INITIALIZERS_EXIST,
114
+
115
+ # make sure we're recording recipes that are being run
116
+ Addons::Recipe::Instructions::Addons::ADDON_RECIPES_INSTALLED_EXISTS,
117
+ # make sure this recipe hasn't been run before
118
+ Addons::Recipe::Instructions::Addons::RECIPE_HASNT_BEEN_RUN_BEFORE,
119
+
120
+ # create config/initializers/addons directory
121
+ Addons::Recipe::Instructions::Rails::RAILS_INITIALIZERS_ADDONS_DIR,
122
+ ]
123
+
124
+ END_RECIPE = [
125
+ # log this recipe installed in addon_recipes_installed.yml
126
+ Addons::Recipe::Instructions::Addons::RECORD_RECIPE_INSTALLED,
127
+ # commit changes in Git
128
+ Addons::Recipe::Instructions::Git::GIT_COMMIT_RECIPE,
129
+ ]
130
+ end
131
+
132
+ end # module Recipe
133
+ end # module Addons
@@ -0,0 +1,233 @@
1
+ module Addons
2
+ module Recipe
3
+
4
+ RECIPE_NAME_PLACEHOLDER = "<RECIPE_NAME_PLACEHOLDER>"
5
+ RECIPE_VERSION_PLACEHOLDER = "<RECIPE_VERSION_PLACEHOLDER>"
6
+ RECIPE_HANDLE_PLACEHOLDER = "<RECIPE_HANDLE_PLACEHOLDER>"
7
+
8
+ @@step_count = 1
9
+ @@no_uncommitted_code_on_start_recipe = false
10
+
11
+ def self.error(instruction, recipe)
12
+ if instruction["error_msg"]
13
+ print_message(instruction["error_msg"], recipe)
14
+ end
15
+ puts "✖"
16
+
17
+ cleanup_git_on_error
18
+ exit
19
+ end
20
+ def self.success(instruction, recipe)
21
+ if instruction["success_msg"]
22
+ print_message(instruction["success_msg"], recipe)
23
+ end
24
+ puts "✓"
25
+ end
26
+ def self.print_message(message, recipe)
27
+ puts gsub_recipe_vars(message, recipe)
28
+ end
29
+ def self.gsub_recipe_vars(message, recipe)
30
+ return message.gsub(RECIPE_VERSION_PLACEHOLDER, recipe["revision"]).gsub(RECIPE_NAME_PLACEHOLDER, recipe["name"]).gsub(RECIPE_HANDLE_PLACEHOLDER, recipe["handle"])
31
+ end
32
+ def self.cleanup_git_on_error
33
+ if @@no_uncommitted_code_on_start_recipe
34
+ # clear any uncommitted code we may have added, ONLY so long as we started with no uncommitted code.
35
+ # NOTE: we definitely don't want to reset a user's own uncommitted code
36
+ instruction = Addons::Recipe::Instructions::Git::GIT_RESET_HARD_HEAD
37
+
38
+ result = `#{instruction["command"]}`
39
+ # print the error message if we didnt get the expected result, use result.include? because GIT_RESET_HARD_HEAD uses CONTAINS_STRING
40
+ puts instruction["error_msg"] unless result.include? instruction["expected_result"]["values"][0]
41
+ end
42
+ end
43
+
44
+ def self.run(recipe)
45
+ puts "\r\nRunning Launchpack.io #{recipe["platform"]} recipe for: #{recipe["name"]}\r\n\r\n"
46
+
47
+ Addons::Recipe::Commons::GIT_READY_RECIPE.each do |git_instruction|
48
+ run_instruction(git_instruction, recipe)
49
+
50
+ # if we didn't exit, and we see all code in Git is committed already, we can reset git if we see an error
51
+ @@no_uncommitted_code_on_start_recipe = true if git_instruction == Addons::Recipe::Instructions::Git::GIT_ALL_CODE_COMMITTED
52
+ end
53
+
54
+ Addons::Recipe::Commons::START_RECIPE.each do |start_instruction|
55
+ run_instruction(start_instruction, recipe)
56
+ end
57
+
58
+ recipe["instructions"].each do |instruction|
59
+ run_instruction(instruction, recipe)
60
+ end # do / instruction
61
+
62
+ Addons::Recipe::Commons::END_RECIPE.each do |end_instruction|
63
+ run_instruction(end_instruction, recipe)
64
+ end
65
+
66
+ end # run
67
+
68
+ def self.run_instruction(instruction, recipe)
69
+ puts "### Step #{@@step_count}: ###"
70
+
71
+ process_instruction(instruction, recipe)
72
+
73
+ puts ""
74
+ @@step_count += 1
75
+ end
76
+
77
+ def self.recipe_tag(recipe, type)
78
+ if type == "comment"
79
+ " \# LAUNCHPACK RECIPE - " + recipe["name"] + " version: " + recipe["revision"]
80
+ elsif type == "start_comment"
81
+ "\# LAUNCHPACK RECIPE COMMENT START - " + recipe["name"] + " version: " + recipe["revision"] + "\n"
82
+ elsif type == "end_comment"
83
+ "\n\# LAUNCHPACK RECIPE COMMENT END - " + recipe["name"] + " version: " + recipe["revision"] + "\n"
84
+ elsif type == "start"
85
+ "\# LAUNCHPACK RECIPE CODE START - " + recipe["name"] + " version: " + recipe["revision"]
86
+ elsif type == "end"
87
+ "\# LAUNCHPACK RECIPE CODE END - " + recipe["name"] + " version: " + recipe["revision"]
88
+ end
89
+ end
90
+
91
+ def self.process_instruction(instruction, recipe)
92
+ print_message(instruction["run_msg"], recipe)
93
+
94
+ case instruction["type"]
95
+
96
+ when InstructionTypes::DIRECTORY_EXISTS
97
+ # check a directory exists
98
+ if Dir.exists?(instruction["command"])
99
+ success(instruction, recipe)
100
+ else
101
+ # exit
102
+ return error(instruction, recipe)
103
+ end
104
+ # end InstructionTypes::DIRECTORY_EXISTS
105
+
106
+ when InstructionTypes::DIRECTORY_CREATE
107
+ # check a directory exists
108
+ if Dir.exists?(instruction["command"]) || Dir.mkdir(instruction["command"])
109
+ success(instruction, recipe)
110
+ else
111
+ # exit
112
+ return error(instruction, recipe)
113
+ end
114
+ # end InstructionTypes::DIRECTORY_CREATE
115
+
116
+ when InstructionTypes::TERMINAL_COMMAND
117
+ result = `#{gsub_recipe_vars(instruction["command"], recipe)}`
118
+
119
+ case instruction["expected_result"]["type"]
120
+ when ResultTypes::NO_EXPECTATION
121
+ success(instruction, recipe)
122
+ when ResultTypes::CONTAINS_STRING
123
+ if result.include? instruction["expected_result"]["values"][0]
124
+ success(instruction, recipe)
125
+ else
126
+ return error(instruction, recipe)
127
+ end
128
+ when ResultTypes::IS_EXACT_STRING
129
+ if instruction["expected_result"]["values"][0] == result
130
+ return success(instruction, recipe)
131
+ else
132
+ return error(instruction, recipe)
133
+ end
134
+ when ResultTypes::DOES_NOT_CONTAIN_STRING
135
+ instruction["expected_result"]["values"].each do |value|
136
+ if result.include?(value)
137
+ return error(instruction, recipe)
138
+ end
139
+ end # end value loop
140
+ success(instruction, recipe)
141
+ end # ResultTypes case
142
+ # end InstructionTypes::TERMINAL_COMMAND
143
+
144
+ when InstructionTypes::MODIFY_CODE
145
+ case instruction["command"]["type"]
146
+ when ModifyCodeTypes::ADD_CODE_REPLACE_FILE
147
+ # open the file for appending
148
+ File.open(instruction["command"]["file"], 'w') do |file|
149
+ file.puts instruction["command"]["code"]
150
+ end
151
+
152
+ success(instruction, recipe)
153
+ when ModifyCodeTypes::ADD_CODE, ModifyCodeTypes::COMMENT_CODE
154
+ # open the file for editing
155
+ if instruction["command"]["comment_code_if"]
156
+ original_content = File.open(instruction["command"]["file"]).read()
157
+ new_file = original_content
158
+ updated = false
159
+
160
+ content_to_comment = original_content.scan(instruction["command"]["comment_code_if"])
161
+
162
+ content_to_comment.each do |content|
163
+ replace_with = recipe_tag(recipe, "start_comment")
164
+ replace_with += content.gsub(/^/, "# ")
165
+ replace_with += recipe_tag(recipe, "end_comment")
166
+
167
+ new_file = new_file.gsub(content, replace_with)
168
+
169
+ updated = true
170
+ end
171
+
172
+ if updated
173
+ File.open(instruction["command"]["file"], "w") do |file|
174
+ file.write(new_file)
175
+ end
176
+ end
177
+ end # end comment_code_if
178
+
179
+ if instruction["command"]["code"]
180
+ File.open(instruction["command"]["file"], 'a+') do |file|
181
+ file.puts ""
182
+ file.puts recipe_tag(recipe, "start")
183
+ file.puts gsub_recipe_vars(instruction["command"]["code"], recipe)
184
+ file.puts recipe_tag(recipe, "end")
185
+ end
186
+ end
187
+
188
+ success(instruction, recipe)
189
+
190
+ when ModifyCodeTypes::ADD_CODE_WITHOUT_TAGS
191
+ File.open(instruction["command"]["file"], 'a+') do |file|
192
+ file.puts gsub_recipe_vars(instruction["command"]["code"], recipe)
193
+ end
194
+
195
+ success(instruction, recipe)
196
+ end # ModifyCodeTypes case
197
+ # end InstructionTypes::MODIFY_CODE
198
+
199
+ when InstructionTypes::SEARCH_AND_COMMENT
200
+ instruction["search_queries"].each_with_index do |query, i|
201
+ search_results = `grep '#{query}' -rI --exclude-dir=\.git ./`
202
+
203
+ if search_results && search_results.length > 0
204
+ # get filenames from each search result
205
+ filenames = search_results.scan(/\.\/\/(.*?):/).uniq
206
+ filenames = filenames.map {|inner_array| inner_array[0] }
207
+
208
+ filenames.each do |filename|
209
+ # create dynamic instruction with filename and instruction["comment_code_if"]
210
+ dynamic_instruction = {
211
+ "run_msg" => "Commenting #{instruction['comment_code_if'][i]} from #{filename}",
212
+ "type" => InstructionTypes::MODIFY_CODE,
213
+ "command" => {
214
+ "type" => ModifyCodeTypes::COMMENT_CODE,
215
+ "file" => filename,
216
+ "comment_code_if" => instruction["comment_code_if"][i],
217
+ },
218
+ "error_msg" => "Error: Could not comment code in #{filename}"
219
+ }
220
+ # process dynamic instruction
221
+ process_instruction dynamic_instruction, recipe
222
+ end
223
+
224
+ end
225
+ end # end search_queries.each
226
+ success(instruction, recipe)
227
+ # end InstructionTypes::SEARCH_AND_COMMENT
228
+
229
+ end # InstructionTypes case
230
+ end # process_instruction
231
+
232
+ end # Recipe
233
+ end # Addons
@@ -0,0 +1,91 @@
1
+ static_recipes = [
2
+ {
3
+ name: "Mailgun SMTP",
4
+ handle: "mailgun_smtp",
5
+ version: "1",
6
+ platform: "Rails 4",
7
+ instructions: [
8
+ # search for existing smtp_settings and comment them out
9
+ {
10
+ run_msg: "Comment exsiting ActionMailer settings throughout the codebase",
11
+ type: InstructionTypes::SEARCH_AND_COMMENT,
12
+ search_queries: ["ActionMailer::Base.delivery_method", "ActionMailer::Base.smtp_settings"],
13
+ comment_code_if: [/ActionMailer::Base.delivery_method\s*=.*$/, /ActionMailer::Base.smtp_settings\s*=\s*{.*}/m],
14
+ error_msg: "Error: Please remove existing ActionMailer::Base.smtp_settings\n(found with: \"grep 'ActionMailer::Base.smtp_settings' -rI --exclude-dir=\.git ./\")"
15
+ },
16
+ # add config/initializers/mailgun.rb
17
+ {
18
+ run_msg: "Adding config/initializers/addons/mailgun_smtp.rb to configure ActiveMailer for Mailgun SMTP",
19
+ type: InstructionTypes::MODIFY_CODE,
20
+ command: {
21
+ type: ModifyCodeTypes::ADD_CODE_REPLACE_FILE,
22
+ file: "config/initializers/addons/mailgun_smtp.rb",
23
+ code: "\
24
+ ActionMailer::Base.smtp_settings = {\n\
25
+ :port => ENV['MAILGUN_SMTP_PORT'],\n\
26
+ :address => ENV['MAILGUN_SMTP_SERVER'],\n\
27
+ :user_name => ENV['MAILGUN_SMTP_LOGIN'],\n\
28
+ :password => ENV['MAILGUN_SMTP_PASSWORD'],\n\
29
+ :domain => 'example.com',\n\
30
+ :authentication => :plain,\n\
31
+ }\n\
32
+ ActionMailer::Base.delivery_method = :smtp\n\
33
+ "
34
+ },
35
+ error_msg: "There was a problem adding Addons::Mailgun.send_simple_email",
36
+ },
37
+ ]
38
+ },
39
+ {
40
+ name: "Mailgun HTTP",
41
+ handle: "mailgun_http",
42
+ version: "1",
43
+ platform: "Rails 4",
44
+ instructions: [
45
+ # install gem rest_client with Gemfile and run from terminal
46
+ {
47
+ run_msg: "Adding gem 'rest_client' to Gemfile",
48
+ type: InstructionTypes::MODIFY_CODE,
49
+ command: {
50
+ type: ModifyCodeTypes::ADD_CODE,
51
+ file: "Gemfile",
52
+ code: "gem 'rest_client'",
53
+ comment_code_if: /rest_client/,
54
+ },
55
+ error_msg: "Error: Could not add gem 'rest_client' to Gemfile"
56
+ },
57
+ Addons::Recipe::Instructions::Bundler::BUNDLER_INSTALL,
58
+ # add Addons::Mailgun.send_simple_email(email) code
59
+ {
60
+ run_msg: "Adding Addons::Mailgun.send_simple_email for sending simple emails",
61
+ type: InstructionTypes::MODIFY_CODE,
62
+ command: {
63
+ type: ModifyCodeTypes::ADD_CODE_REPLACE_FILE,
64
+ file: "config/initializers/addons/mailgun_http.rb",
65
+ code: "\
66
+ require 'rest_client'\n\
67
+ \n\
68
+ module Addons\n\
69
+ class Mailgun\n\
70
+ def self.send_simple_message(email)\n\
71
+ from = email[:from] || email[\"from\"] || email.from\n\
72
+ to = email[:to] || email[\"to\"] || email.to\n\
73
+ subject = email[:subject] || email[\"subject\"] || email.subject\n\
74
+ body = email[:body] || email[\"body\"] || email.body\n\
75
+ \n\
76
+ RestClient.post \"https://api:\#{ENV['MAILGUN_API_KEY']}\"\\\n\
77
+ \"@api.mailgun.net/v2/\#{ENV['MAILGUN_SMTP_LOGIN'].match(/@(.*)$/)[1]}/messages\",\n\
78
+ :from => from,\n\
79
+ :to => to,\n\
80
+ :subject => subject,\n\
81
+ :text => body\n\
82
+ end\n\
83
+ end # Mailgun\n\
84
+ end # Addons\n\
85
+ "
86
+ },
87
+ error_msg: "There was a problem adding Addons::Mailgun.send_simple_email",
88
+ },
89
+ ]
90
+ }, # end Mailgun HTTP
91
+ ]
@@ -0,0 +1,23 @@
1
+ class InstructionTypes
2
+ DIRECTORY_EXISTS = 0
3
+ DIRECTORY_CREATE = 1
4
+ TERMINAL_COMMAND = 2
5
+ MODIFY_CODE = 3
6
+ SEARCH_AND_COMMENT = 4
7
+ end
8
+
9
+ class ResultTypes
10
+ DOES_NOT_CONTAIN_STRING = 0
11
+ NO_EXPECTATION = 1
12
+ IS_EXACT_STRING = 2
13
+ CONTAINS_STRING = 3
14
+ end
15
+
16
+ class ModifyCodeTypes
17
+ COMMENT_CODE = 0
18
+ ADD_CODE = 1
19
+ REMOVE_CODE = 2
20
+ REPLACE_CODE = 3
21
+ ADD_CODE_REPLACE_FILE = 4
22
+ ADD_CODE_WITHOUT_TAGS = 5
23
+ end
@@ -1,3 +1,3 @@
1
1
  module Addons
2
- VERSION = "0.0.9"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -26,6 +26,30 @@ module Addons
26
26
  create_file "config/initializers/addons.rb", "# Addons initializer content\nAddons::Config.init()"
27
27
  end
28
28
 
29
+ def add_application_yml_to_gitignore
30
+ # gitignore config/application.yml so we aren't storing sensitive info in .git
31
+ # TODO: replace figaro with figaro-addons and application.yml with addons.yml
32
+ gitignore = Rails.root.join('.gitignore')
33
+ if File.readlines(gitignore).grep(/config\/application.yml/).size == 0
34
+ File.open(gitignore, 'a') do |file|
35
+ file.puts 'config/application.yml'
36
+ end
37
+ end
38
+ end
39
+
40
+ def add_figaro_gem
41
+ figaro = Rails.root.join('Gemfile')
42
+ if File.readlines(figaro).grep(/gem 'figaro'/).size == 0
43
+ File.open(figaro, 'a') do |file|
44
+ file.puts ""
45
+ file.puts "gem 'figaro' # Addons dependency"
46
+ end
47
+ end
48
+
49
+ # bundle install
50
+ result = `bundle install`
51
+ end
52
+
29
53
  def bootstrap_app_id_and_token
30
54
  # write config/application.yml to load env vars on startup
31
55
  filename = Rails.root.join('config', 'application.yml')
@@ -0,0 +1,44 @@
1
+ require 'rest_client'
2
+ require 'json'
3
+
4
+ require 'addons/recipes/types'
5
+ require 'addons/recipes/recipe'
6
+ require 'addons/recipes/instructions'
7
+
8
+ namespace :addons do
9
+ namespace :recipe do
10
+
11
+ desc "Run a recipe by name"
12
+ task :run, :recipe_handle do |t, args|
13
+ recipes = nil
14
+ recipeUrl = "https://launchpack.io/api/v1/apps/recipes?app_id=#{ENV['ADDONS_APP_ID']}&app_token=#{ENV['ADDONS_APP_TOKEN']}"
15
+
16
+ response = RestClient.get recipeUrl
17
+ recipes = JSON.parse response.body
18
+
19
+ # parse instructions into ruby
20
+ recipes.each { |recipe| recipe["instructions"] = JSON.parse(recipe["instructions"]) }
21
+
22
+ @run = false
23
+ if "all" == args[:recipe_handle]
24
+ puts "Running all your Launchpack.io recipes"
25
+
26
+ recipes.each do |recipe|
27
+ Addons::Recipe.run recipe
28
+ end
29
+ elsif handle = args[:recipe_handle]
30
+ recipes.each do |recipe|
31
+ # run recipe if it's the correct one
32
+ if handle == recipe["handle"]
33
+ @run = true
34
+ Addons::Recipe.run recipe
35
+ end
36
+ end
37
+ puts "Error: Recipe not found." unless @run
38
+ else
39
+ puts "Error: Incorrect usage. Expecting: `rake addons:recipe:run[recipe_handle]`"
40
+ end
41
+ end # end task: run
42
+
43
+ end # end namespace: recipe
44
+ end # end namespace: addons
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: addons
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Addonlist
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-08 00:00:00.000000000 Z
11
+ date: 2014-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest_client
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'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: json
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,20 @@ dependencies:
38
52
  - - '>='
39
53
  - !ruby/object:Gem::Version
40
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: bundler
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -96,8 +124,14 @@ files:
96
124
  - addons.gemspec
97
125
  - lib/addons.rb
98
126
  - lib/addons/config.rb
127
+ - lib/addons/railtie.rb
128
+ - lib/addons/recipes/instructions.rb
129
+ - lib/addons/recipes/recipe.rb
130
+ - lib/addons/recipes/recipes.rb
131
+ - lib/addons/recipes/types.rb
99
132
  - lib/addons/version.rb
100
133
  - lib/generators/addons/install_generator.rb
134
+ - lib/tasks/addons_recipe.rake
101
135
  - spec/addons_spec.rb
102
136
  homepage: ''
103
137
  licenses: