woro 0.1.0 → 0.2.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: 5a7d57892a65138472c52bcf5c91ead031cd022f
4
- data.tar.gz: 5fc6dbd1d5e0ab491f9e06a1d17b87ccc69e86bd
3
+ metadata.gz: 9280b0c23821f1b2f349fb0653519a738e12640b
4
+ data.tar.gz: 9a96cbb374926861269b29bfbc7536b966478a79
5
5
  SHA512:
6
- metadata.gz: f0dda43342aab660543a9b115438ab7322ef00242a767518818ec7f81701f25efac7935b3973f2cbe2431819530d929906a489e1e0ead0fda3fc98ecf75fe7b8
7
- data.tar.gz: 0a7e6eff1e8467046c18dfdf13eb3111865737438bbdac1f49f76d503ee95585a0c0441e8d630bb8e621099493b5c93ce84f85406a7aeffd2575b93295c8fece
6
+ metadata.gz: bab818aa8921e7c73e0f7cd124550336fb35c25f8e725e21056e5cc197787da6d76e06225252a3e35798f8548f977c9f10dfcd3c8570106e859015fb831b74d0
7
+ data.tar.gz: f73111d88b02d1e23e25a588d718b2d42862e5bccc02493a8318c5d6a666ccd229c0b809972e92ba9893a801a97559b5183acf79734816f0de8bce886f6d5dfd
data/Gemfile CHANGED
@@ -2,3 +2,10 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in woro.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem 'aruba'
8
+ gem "rspec"
9
+ gem "rspec-nc"
10
+ gem 'fakefs'
11
+ end
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Write once, run once.
4
4
 
5
5
  Manage one-time remote tasks in your Rails project.
6
- Plugins with Mina to add support for rake tasks hosted in remote collection, such as Gist.
6
+ Plugins with Mina and Capistrano to add support for rake tasks hosted in remote collection, such as Gist.
7
7
 
8
8
  Say you have a data migration to perform on a remote server. The procedure is too complex to just do it in the remote console and using database migrations would be evil. A rake task would be nice, but checking this in with the source code repository adds clutter, as you know you will only run this once.
9
9
  Woro offers a quick way of pushing rake tasks onto the remote server, execute them and delete them instantly. Using Github's gist, you keep version control of the tasks and can share them with colleagues.
@@ -32,6 +32,17 @@ Or install it yourself as:
32
32
  $ gem install woro
33
33
  ```
34
34
 
35
+ Then run:
36
+
37
+ ```shell
38
+ $ woro init
39
+ ```
40
+
41
+ This will create `lib/woro_tasks/` folder and `lib/tasks/woro.rake`.
42
+ Here the Woro task files are stored, edited locally and run using rake.
43
+
44
+ ### for use with Mina
45
+
35
46
  Require `mina/woro` in your `config/deploy.rb`:
36
47
 
37
48
  ```rb
@@ -41,33 +52,26 @@ require 'mina/git'
41
52
  require 'mina/woro'
42
53
 
43
54
  ...
55
+ ```
44
56
 
45
- task setup: :environment do
46
- ...
47
- end
57
+ ### for use with Capistrano
48
58
 
49
- desc 'Deploys the current version to the server.'
50
- task deploy: :environment do
51
- ...
52
- end
53
- ```
59
+ Require `capistrano/woro` in your `config/deploy.rb`:
54
60
 
55
- Then run:
61
+ ```rb
62
+ require 'capistrano/rails'
63
+ require 'capistrano/woro'
56
64
 
57
- ```shell
58
- $ woro init
65
+ ...
59
66
  ```
60
67
 
61
- This will create `lib/woro_tasks/` folder and `lib/tasks/woro.rake`.
62
- Here the Woro task files are stored and edited locally.
63
-
64
68
  ## Usage
65
69
 
66
70
  ```shell
67
71
  $ woro new cleanup_users
68
72
  ```
69
73
 
70
- Can be used to create the template for a new task in `lib/tasks/`.
74
+ Can be used to create the template for a new task in `lib/woro_tasks/`.
71
75
 
72
76
  The task itself is a regular rake-task in the woro-namespace. You can test it locally using rake:
73
77
 
@@ -76,33 +80,39 @@ $ rake woro:cleanup_users
76
80
  ```
77
81
 
78
82
  Once you are done writing the task and you want to execute it on the remote system.
79
- First you have to push them online.
83
+ First you have to push them online, in this case to Gist.
80
84
 
81
85
  ```shell
82
- $ woro push cleanup_users
86
+ $ woro push gist:cleanup_users
83
87
  ```
84
88
 
85
89
  _Attention, depending on whether you set up a Gist/Github login on
86
90
  initialization. These tasks are online anonymous, but public, or
87
91
  private under the specified Github account._
88
92
 
93
+ Now, to run a task remotely using Mina, specify the task:
94
+
95
+ ```shell
96
+ $ mina woro:run task=gist:cleanup_users
97
+ ```
89
98
 
90
- Now, to run a task remotely using mina, specify the task:
99
+ Or to run it with Capistrano:
91
100
 
92
101
  ```shell
93
- $ mina woro:run task=cleanup_users
102
+ $ cap woro:run task=gist:cleanup_users
94
103
  ```
95
104
 
96
- To show a list of all uploaded tasks do:
105
+ To show a list of all tasks uploaded to any collection do:
97
106
 
98
107
  ```shell
99
108
  $ woro list
109
+ $ woro ls
100
110
  ```
101
111
 
102
- And finally you can download an existing task:
112
+ And finally you can download an existing task to your local woro tasks directory.
103
113
 
104
114
  ```shell
105
- $ woro pull cleanup_users
115
+ $ woro pull gist:cleanup_users
106
116
  ```
107
117
 
108
118
  ## Contributing
data/bin/woro CHANGED
@@ -32,33 +32,32 @@ command :init do |c|
32
32
 
33
33
  if agree 'Login to Gist/Github for private Woro tasks (Yes/No)? '
34
34
  Gist.login!
35
- #else
36
- #gen_access_token = agree "Secure gists via random access token?"
37
- end
35
+ #elsif agree 'Login to AWS/S3 for private Woro tasks (Yes/No)? '
38
36
 
37
+ end
38
+ # if none of these, use gist, but public
39
39
 
40
40
  # create Gist with welcome file
41
41
  # additional tasks will be added to this first gist
42
42
  app_name = ask 'Application name: '
43
- result = Woro::Gister.create_initial_gist(app_name)
43
+ result = Woro::Adapters::Gist.create_initial_remote_task(app_name)
44
44
 
45
45
  # configure adapters
46
46
  gist_adapter = {
47
47
  gist_id: result['id'],
48
48
  public: false
49
49
  }
50
- # TODO generate access token
51
- #gist_adapter[:access_token] = 'access_token' if gen_access_token
52
- adapters = { gist: gist_adapter }
53
50
 
54
51
  unless File.exists? File.dirname(Woro::Configuration.config_file)
55
52
  FileUtils.mkdir_p File.dirname(Woro::Configuration.config_file)
56
53
  end
57
- config = Woro::Configuration.save(adapters: adapters)
58
54
  say 'Initialized at `./config/woro.yml`'
59
55
 
56
+ options.default(adapters: { gist: gist_adapter } )
57
+ config = Woro::Configuration.save(options.__hash__)
58
+
60
59
  unless File.exists? config.woro_task_dir
61
- FileUtils.mkdir_p
60
+ FileUtils.mkdir_p config.woro_task_dir
62
61
  say "Create #{config.woro_task_dir}"
63
62
  end
64
63
 
@@ -76,10 +75,10 @@ command :new do |c|
76
75
  c.example 'Creates tasks called "cleanup", "fix1" and "fix2"', 'woro new cleanup fix1 fix2'
77
76
  c.option '--[no-]force', 'force overwrite of existing task file'
78
77
  c.action do |args, options|
79
- args.each do |arg|
80
- config = Woro::Configuration.load
81
- task = Woro::Task.new(config.adapters[:gist][:gist_id], arg)
82
- force_overwrite = options.force
78
+ config = Woro::Configuration.load
79
+ force_overwrite = options.force
80
+ args.each do |task_name|
81
+ task = Woro::Task.new(task_name)
83
82
  if !task.exists? || force_overwrite || agree("Overwrite existing #{task.file_path}?")
84
83
  task.create_from_task_template
85
84
  say "Created #{task.file_path}"
@@ -94,12 +93,18 @@ command :push do |c|
94
93
  c.description = 'Pushes one or more local tasks to the remote collection. Existing tasks by this name in the remote connection will be updated.'
95
94
  c.example 'Pushes the task "cleanup" to the remote collection', 'woro push cleanup'
96
95
  c.action do |args, options|
96
+ config = Woro::Configuration.load
97
97
  args.each do |arg|
98
- config = Woro::Configuration.load
98
+ unless arg.include?(':')
99
+ say_error "Does not specify upload target"
100
+ next
101
+ end
102
+ adapter_name, task_name = arg.split(':')
103
+ adapter = config.adapter adapter_name
99
104
  # Pushes a new woro task by given name to gist, this can be done multiple time.
100
- task = Woro::Task.new(config.adapters[:gist][:gist_id], arg)
105
+ task = Woro::Task.new(task_name)
101
106
  if task.exists?
102
- result = task.push
107
+ result = adapter.push(task)
103
108
  say "Uploaded #{task.file_path} to #{result['url']}"
104
109
  else
105
110
  say "Task #{task.task_name} not found at #{task.file_path}"
@@ -112,16 +117,23 @@ command :pull do |c|
112
117
  c.syntax = 'woro pull <task> [options]'
113
118
  c.summary = 'Pull Woro task from remote repository'
114
119
  c.description = 'Pulls one task from the remote collection. Existing local tasks can be overwritten.'
115
- c.example 'Pulls the task "cleanup" from the remote collection', 'woro pull cleanup'
120
+ c.example 'Pulls the task "cleanup" from the remote collection', 'woro pull gist:cleanup'
116
121
  c.option '--[no-]force', 'force overwrite of existing task file'
117
122
  c.action do |args, options|
118
123
  config = Woro::Configuration.load
119
- # Pulls the woro task by given name to gist, this can be done multiple time.
120
- task = Woro::Task.new(config.adapters[:gist][:gist_id], args.first)
121
- force_save = options.force
122
- if !task.exists? || force_overwrite || agree("Overwrite existing #{task.file_path}?")
123
- system "cd '#{config.woro_task_dir}' && curl -O -# #{task.raw_url}"
124
- say "Downloaded #{task.task_name} to #{task.file_path}"
124
+ args.each do |arg|
125
+ unless arg.include?(':')
126
+ say_error "Does not specify download target"
127
+ next
128
+ end
129
+ adapter_name, task_name = arg.split(':')
130
+ adapter = config.adapter adapter_name
131
+ task = Woro::Task.new(task_name)
132
+ force_overwrite = options.force
133
+ if !task.exists? || force_overwrite || agree("Overwrite existing #{task.file_path}?")
134
+ system "cd '#{config.woro_task_dir}' && curl -O -# #{adapter.raw_url(task.file_name)}"
135
+ say "Downloaded #{task.task_name} to #{task.file_path}"
136
+ end
125
137
  end
126
138
  end
127
139
  end
@@ -135,13 +147,25 @@ command :list do |c|
135
147
  c.action do |args, options|
136
148
  abort "invalid command. See 'woro help' for more information" unless args.empty?
137
149
  config = Woro::Configuration.load
138
- files = Woro::Gister.get_list_of_files config.adapters[:gist][:gist_id]
139
- tasks = files.map { |file_name, data| OpenStruct.new(name_with_args: file_name.split('.rake').first, comment: Woro::Gister.extract_description(data)) if file_name.include? '.rake' }
140
- tasks.compact!
141
- width ||= tasks.map { |t| t.name_with_args.length }.max || 10
142
- tasks.each do |t|
143
- puts " %-#{width}s # %s" % [ t.name_with_args, t.comment ]
150
+ config.adapters.each do |adapter_config|
151
+ puts "#{adapter_config[0]} ---"
152
+ adapter = config.adapter(adapter_config[0])
153
+ files = adapter.list_keys || {}
154
+ tasks = files.map do |file_name, data|
155
+ if file_name.include? '.rake'
156
+ OpenStruct.new(name_with_args: file_name.split('.rake').first,
157
+ comment: adapter.extract_description(data))
158
+ end
159
+ end
160
+ tasks.compact!
161
+ Woro::TaskHelper.print_task_list(tasks)
162
+ end
163
+ puts "local ---"
164
+ tasks = Woro::TaskHelper.woro_task_files(config.woro_task_dir) do |file_name, data|
165
+ OpenStruct.new(name_with_args: file_name.split('.rake').first,
166
+ comment: Woro::TaskHelper.extract_description(data))
144
167
  end
168
+ Woro::TaskHelper.print_task_list(tasks)
145
169
  end
146
170
  end
147
171
  alias_command :ls, :list
@@ -0,0 +1 @@
1
+ load File.expand_path("../../woro/tasks/capistrano.rake", __FILE__)
data/lib/woro.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require 'woro/version'
2
+ require 'woro/task_helper'
2
3
  require 'woro/task'
3
- require 'woro/gister'
4
+ require 'woro/adapters/s3'
5
+ require 'woro/adapters/gist'
4
6
  require 'woro/configuration'
@@ -0,0 +1,82 @@
1
+ require 'gist'
2
+
3
+ module Woro
4
+ module Adapters
5
+ class Gist
6
+
7
+ attr_reader :gist_id
8
+
9
+ # Create a new gist collection adapter
10
+ # @param gist_id [String] gist to which the adapter connects
11
+ def initialize(gist_id)
12
+ @gist_id = gist_id
13
+ end
14
+
15
+ # Returns the list of files included in the Gist
16
+ # @return [Hash] List of files in the format { filename: { data }}
17
+ def list_keys
18
+ gist['files']
19
+ end
20
+
21
+ # Push this task's file content to the Gist collection on the server.
22
+ # Existing contents by the same #file_name will be overriden, but
23
+ # can be accessed via Github or Gist's API.
24
+ def push(task)
25
+ ::Gist.multi_gist({ task.file_name => task.read_task_file },
26
+ public: false,
27
+ update: gist_id,
28
+ output: :all)
29
+ end
30
+
31
+ # The Gist contains a collection of files.
32
+ # These are stored and accessed on Github.
33
+ # @return [Hash] parsed JSON hash of the gist's metadata
34
+ def gist
35
+ @gist ||= retrieve_gist(gist_id)
36
+ end
37
+
38
+ # Retrieves metadata of the specified gist
39
+ # @param gist_id [String] id of the gist
40
+ # @return [Hash] parsed JSON hash
41
+ def retrieve_gist(gist_id)
42
+ service_url = "https://api.github.com/gists/#{gist_id}"
43
+ response = Net::HTTP.get_response(URI.parse(service_url))
44
+ JSON.parse(response.body || '')
45
+ end
46
+
47
+ # Retrieves the data hash included in the gist under the #file_name.
48
+ # @param file_name [String] name of the file to retrieve the download url
49
+ # @return [Hash] parsed JSON hash
50
+ def retrieve_file_data(file_name)
51
+ gist['files'][file_name]
52
+ end
53
+
54
+ # The raw url is a permalink for downloading the content rake task within
55
+ # the Gist as a file.
56
+ # @param file_name [String] name of the file to retrieve the download url
57
+ # @return [String] HTTP-URL of addressed file within the gist collection
58
+ def raw_url(file_name)
59
+ retrieve_file_data(file_name)['raw_url']
60
+ end
61
+
62
+ # Creates an initial welcome gist on project setup
63
+ # @param app_name [String] Name of the app is displayed in the initial welcome message
64
+ def self.create_initial_remote_task(app_name, access_token=nil)
65
+ ::Gist.gist("Welcome to the Woro Task Repository for #{app_name}", filename: app_name, access_token: access_token)
66
+ end
67
+
68
+ # Extract description from gist's data content string.
69
+ # @param data [Hash] gist data hash
70
+ # [String] description string
71
+ def extract_description(data)
72
+ Woro::TaskHelper.extract_description(data['content'])
73
+ end
74
+
75
+ # Read the rake task template
76
+ # @return [String]
77
+ def read_template_file
78
+ File.read(File.join(File.dirname(__FILE__), 'templates','task.rake') )
79
+ end
80
+ end
81
+ end
82
+ end
@@ -4,12 +4,13 @@ include Commander::UI
4
4
 
5
5
  module Woro
6
6
  class Configuration
7
- attr_reader :adapters, :woro_task_dir
7
+ attr_reader :adapters, :woro_task_dir, :app_name
8
8
 
9
9
  # Initialize configuration.
10
10
  def initialize(options = {})
11
11
  @woro_task_dir = Configuration.woro_task_dir
12
12
  @adapters = options[:adapters]
13
+ @app_name = options[:app_name]
13
14
  end
14
15
 
15
16
  # Load configuration file or default_options. Passed options take precedence.
@@ -17,7 +18,7 @@ module Woro
17
18
  user_options = options.reject{|k,v| ![:adapters, :app_name].include? k}
18
19
 
19
20
  if !(File.exists? config_file)
20
- File.open(config_file, 'w') { |file| YAML::dump(default_options, file) }
21
+ File.open(config_file, 'w') { |file| YAML.dump(default_options, file) }
21
22
  say "Initialized default config file in #{config_file}. See 'woro help init' for options."
22
23
  end
23
24
 
@@ -31,7 +32,7 @@ module Woro
31
32
  force_save = options.delete :force
32
33
 
33
34
  if !(File.exists? config_file) || force_save
34
- File.open(config_file, 'w') { |file| YAML::dump(default_options.merge(user_options), file) }
35
+ File.open(config_file, 'w') { |file| YAML.dump(default_options.merge(user_options), file) }
35
36
  say "Initialized config file in #{config_file}"
36
37
  else
37
38
  say_error "Not overwriting existing config file #{config_file}, use --force to override. See 'woro help init'."
@@ -39,6 +40,15 @@ module Woro
39
40
  self
40
41
  end
41
42
 
43
+ def adapter(name)
44
+ options = adapters[name.to_sym]
45
+
46
+ case name.to_sym
47
+ when :gist
48
+ @gist_adapter ||= Woro::Adapters::Gist.new(options[:gist_id])
49
+ end
50
+ end
51
+
42
52
  # Helpers
43
53
 
44
54
  def self.config_file
data/lib/woro/task.rb CHANGED
@@ -4,25 +4,22 @@ require 'erb'
4
4
  module Woro
5
5
  # Task object, helps in the creation and management of gists.
6
6
  class Task
7
- attr_reader :task_name, :gist_id, :gist
7
+ attr_reader :task_name, :gist
8
8
 
9
- def initialize(gist_id, task_name)
9
+ def initialize(task_name)
10
10
  @task_name = Woro::Task.sanitize_task_name task_name
11
- @gist_id = gist_id
12
11
  end
13
12
 
14
- # Create a new task based on a template rake-task.
15
- # @param gist_id [String] gist to which the task is added
16
13
  # @param task_name [String] sanitized name of the task, used throughout the further processing
17
14
  # @return [Task] the created task
18
- def self.create(gist_id, task_name)
19
- task = Woro::Task.new(gist_id, task_name)
15
+ def self.create(task_name)
16
+ task = Woro::Task.new(task_name)
20
17
  task.create_from_task_template
21
18
  task
22
19
  end
23
20
 
24
21
  def self.sanitize_task_name(task_name)
25
- task_name.strip.split(' ').first
22
+ task_name.strip.split(' ').first # not nice
26
23
  end
27
24
 
28
25
  # File name based on the task's name.
@@ -34,18 +31,18 @@ module Woro
34
31
  # File name based on the task's filename (see #file_name).
35
32
  # @return [String]
36
33
  def file_path
37
- File.join('lib','woro_tasks', file_name)
34
+ File.join 'lib', 'woro_tasks', file_name
38
35
  end
39
36
 
40
37
  # Returns true if a task of this name exists locally
41
38
  def exists?
42
- File.exists? file_path
39
+ File.exist? file_path
43
40
  end
44
41
 
45
42
  # Creates a new rake task file at the file path (see #file_path).
46
43
  def create_from_task_template
47
44
  b = binding
48
- template = ERB.new(Gister.read_template_file).result(b)
45
+ template = ERB.new(Woro::TaskHelper.read_template_file).result(b)
49
46
  File.open(file_path, 'w') do |f|
50
47
  f.puts template
51
48
  end
@@ -63,34 +60,5 @@ module Woro
63
60
  def read_task_file
64
61
  File.read(file_path)
65
62
  end
66
-
67
- # Push this task's file content to the Gist collection on the server.
68
- # Existing contents by the same #file_name will be overriden, but
69
- # can be accessed via Github or Gist's API.
70
- def push
71
- Gist.multi_gist({ file_name => read_task_file },
72
- public: false,
73
- update: gist_id,
74
- output: :all)
75
- end
76
-
77
- # The Gist contains a collection of files.
78
- # These are stored and accessed on Github.
79
- # @return [Hash] parsed JSON hash of the gist's metadata
80
- def gist
81
- @gist ||= Gister.retrieve_gist(gist_id)
82
- end
83
-
84
- # Retrieves the data hash included in the gist under the #file_name.
85
- # @return [Hash] parsed JSON hash
86
- def retrieve_file_data
87
- gist['files'][file_name]
88
- end
89
-
90
- # The raw url is a permalink for downloading the content rake task within
91
- # the Gist as a file.
92
- def raw_url
93
- retrieve_file_data['raw_url']
94
- end
95
63
  end
96
64
  end
@@ -0,0 +1,39 @@
1
+ module Woro
2
+ class TaskHelper
3
+
4
+ class << self
5
+
6
+ def print_task_list(tasks)
7
+ width ||= tasks.map { |t| t.name_with_args.length }.max || 10
8
+ tasks.each do |t|
9
+ puts " %-#{width}s # %s" % [ t.name_with_args, t.comment ]
10
+ end
11
+ end
12
+
13
+ # Perform an action over all files within the woro task directory
14
+ def woro_task_files(directory, &block)
15
+ tasks = []
16
+ Dir.foreach(directory) do |file_name|
17
+ if file_name.include? '.rake'
18
+ data = File.read(File.join(directory, file_name))
19
+ tasks << yield(file_name, data)
20
+ end
21
+ end
22
+ tasks
23
+ end
24
+
25
+ # Extract description from gist's data content string.
26
+ # @param data [Hash] gist data hash
27
+ # [String] description string
28
+ def extract_description(task_content)
29
+ task_content.match(/desc ['"]([a-zA-Z0-9\s]*)['"]/)[1]
30
+ end
31
+
32
+ # Read the rake task template
33
+ # @return [String]
34
+ def read_template_file
35
+ File.read(File.join(File.dirname(__FILE__), 'templates','task.rake') )
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,58 +1,31 @@
1
- require 'ostruct'
2
- require 'woro/gister'
3
- require 'woro/task'
4
-
5
- # Capistrano Recipes for managing woro tasks
6
- #
7
- # Add these callbacks to have the delayed_job process restart when the server
8
- # is restarted:
9
- #
10
- # after "deploy:stop", "delayed_job:stop"
11
- # after "deploy:start", "delayed_job:start"
12
- # after "deploy:restart", "delayed_job:restart"
13
- #
14
- # If you want to use command line options, for example to start multiple workers,
15
- # define a Capistrano variable delayed_job_args:
16
- #
17
- # set :delayed_job_args, "-n 2"
18
- #
19
- # If you've got delayed_job workers running on a servers, you can also specify
20
- # which servers have delayed_job running and should be restarted after deploy.
21
- #
22
- # set :delayed_job_server_role, :worker
23
- #
24
-
25
- Capistrano::Configuration.instance.load do
26
- namespace :delayed_job do
27
- def rails_env
28
- fetch(:rails_env, false) ? "RAILS_ENV=#{fetch(:rails_env)}" : ''
29
- end
30
-
31
- def args
32
- fetch(:delayed_job_args, '')
33
- end
34
-
35
- def roles
36
- fetch(:delayed_job_server_role, :app)
37
- end
38
-
39
- def delayed_job_command
40
- fetch(:delayed_job_command, 'script/delayed_job')
41
- end
42
-
43
- desc 'Stop the delayed_job process'
44
- task :stop, :roles => lambda { roles } do
45
- run "cd #{current_path} && #{rails_env} #{delayed_job_command} stop #{args}"
46
- end
47
-
48
- desc 'Start the delayed_job process'
49
- task :start, :roles => lambda { roles } do
50
- run "cd #{current_path} && #{rails_env} #{delayed_job_command} start #{args}"
51
- end
52
-
53
- desc 'Restart the delayed_job process'
54
- task :restart, :roles => lambda { roles } do
55
- run "cd #{current_path} && #{rails_env} #{delayed_job_command} restart #{args}"
1
+ require 'woro'
2
+
3
+ # Capistrano recipees for managing woro tasks
4
+ namespace :woro do
5
+ desc 'Run Woro task remotely'
6
+ task run: 'deploy:set_rails_env' do
7
+
8
+ on roles(:app), in: :sequence, wait: 5 do
9
+ unless ENV['task'].include?(':')
10
+ error "Does not specify upload target"
11
+ else
12
+ config = Woro::Configuration.load
13
+
14
+ adapter_name, task_name = ENV['task'].split(':')
15
+ adapter = config.adapter(adapter_name)
16
+ task = Woro::Task.new(task_name)
17
+
18
+ info "Execute #{task.task_name} remotely"
19
+ within File.join(release_path, 'lib', 'tasks') do
20
+ execute :curl, "#{adapter.raw_url(task.file_name)}", '-o' "woro_#{task.file_name}"
21
+ end
22
+ within release_path do
23
+ with rails_env: fetch(:rails_env) do
24
+ execute :rake, "woro:#{task.task_name}"
25
+ execute :rm, "lib/tasks/woro_#{task.file_name}"
26
+ end
27
+ end
28
+ end
56
29
  end
57
30
  end
58
31
  end
@@ -6,12 +6,18 @@ namespace :woro do
6
6
  desc 'Run Woro task remotely'
7
7
  task run: :environment do
8
8
  config = Woro::Configuration.load
9
- task = Woro::Task.new(config.adapter[:gist][:gist_id], ENV['task'])
9
+ unless ENV['task'].include?(':')
10
+ print_error "Does not specify upload target"
11
+ return
12
+ end
13
+ adapter_name, task_name = ENV['task'].split(':')
14
+ adapter = config.adapter(adapter_name)
15
+ task = Woro::Task.new(task_name)
10
16
  print_status "Execute #{task.task_name} remotely"
11
17
  in_directory "#{app_path}" do
12
- queue! "cd 'lib/tasks' && curl -O #{task.raw_url}"
18
+ queue! "cd 'lib/tasks' && curl #{adapter.raw_url(task.file_name)} -o woro_#{task.file_name}"
13
19
  queue! "#{bundle_prefix} rake woro:#{task.task_name}"
14
- queue! "rm lib/tasks/#{task.file_name}"
20
+ queue! "rm lib/tasks/woro_#{task.file_name}"
15
21
  end
16
22
  end
17
23
  end
data/lib/woro/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Woro
2
2
  # Look shiny!
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
@@ -0,0 +1,6 @@
1
+ namespace :woro do
2
+ desc 'Write your description here'
3
+ task <%= task_name %>: :environment do
4
+ # your code
5
+ end
6
+ end
@@ -0,0 +1,103 @@
1
+ {
2
+ "url": "https://api.github.com/gists/aa5a315d61ae9438b18d",
3
+ "forks_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/forks",
4
+ "commits_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/commits",
5
+ "id": "aa5a315d61ae9438b18d",
6
+ "description": "description of gist",
7
+ "public": true,
8
+ "owner": {
9
+ "login": "octocat",
10
+ "id": 1,
11
+ "avatar_url": "https://github.com/images/error/octocat_happy.gif",
12
+ "gravatar_id": "",
13
+ "url": "https://api.github.com/users/octocat",
14
+ "html_url": "https://github.com/octocat",
15
+ "followers_url": "https://api.github.com/users/octocat/followers",
16
+ "following_url": "https://api.github.com/users/octocat/following{/other_user}",
17
+ "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
18
+ "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
19
+ "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
20
+ "organizations_url": "https://api.github.com/users/octocat/orgs",
21
+ "repos_url": "https://api.github.com/users/octocat/repos",
22
+ "events_url": "https://api.github.com/users/octocat/events{/privacy}",
23
+ "received_events_url": "https://api.github.com/users/octocat/received_events",
24
+ "type": "User",
25
+ "site_admin": false
26
+ },
27
+ "user": null,
28
+ "files": {
29
+ "create_user.rake": {
30
+ "size": 932,
31
+ "raw_url": "https://gist.githubusercontent.com/raw/365370/8c4d2d43d178df44f4c03a7f2ac0ff512853564e/ring.erl",
32
+ "type": "text/plain",
33
+ "language": "Ruby",
34
+ "truncated": false,
35
+ "content": "namespace :woro do\n desc 'Create User'\n task create_user: :environment do\n # Code\n end\nend\n"
36
+ }
37
+ },
38
+ "comments": 0,
39
+ "comments_url": "https://api.github.com/gists/aa5a315d61ae9438b18d/comments/",
40
+ "html_url": "https://gist.github.com/aa5a315d61ae9438b18d",
41
+ "git_pull_url": "https://gist.github.com/aa5a315d61ae9438b18d.git",
42
+ "git_push_url": "https://gist.github.com/aa5a315d61ae9438b18d.git",
43
+ "created_at": "2010-04-14T02:15:15Z",
44
+ "updated_at": "2011-06-20T11:34:15Z",
45
+ "forks": [
46
+ {
47
+ "user": {
48
+ "login": "octocat",
49
+ "id": 1,
50
+ "avatar_url": "https://github.com/images/error/octocat_happy.gif",
51
+ "gravatar_id": "",
52
+ "url": "https://api.github.com/users/octocat",
53
+ "html_url": "https://github.com/octocat",
54
+ "followers_url": "https://api.github.com/users/octocat/followers",
55
+ "following_url": "https://api.github.com/users/octocat/following{/other_user}",
56
+ "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
57
+ "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
58
+ "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
59
+ "organizations_url": "https://api.github.com/users/octocat/orgs",
60
+ "repos_url": "https://api.github.com/users/octocat/repos",
61
+ "events_url": "https://api.github.com/users/octocat/events{/privacy}",
62
+ "received_events_url": "https://api.github.com/users/octocat/received_events",
63
+ "type": "User",
64
+ "site_admin": false
65
+ },
66
+ "url": "https://api.github.com/gists/dee9c42e4998ce2ea439",
67
+ "id": "dee9c42e4998ce2ea439",
68
+ "created_at": "2011-04-14T16:00:49Z",
69
+ "updated_at": "2011-04-14T16:00:49Z"
70
+ }
71
+ ],
72
+ "history": [
73
+ {
74
+ "url": "https://api.github.com/gists/aa5a315d61ae9438b18d/57a7f021a713b1c5a6a199b54cc514735d2d462f",
75
+ "version": "57a7f021a713b1c5a6a199b54cc514735d2d462f",
76
+ "user": {
77
+ "login": "octocat",
78
+ "id": 1,
79
+ "avatar_url": "https://github.com/images/error/octocat_happy.gif",
80
+ "gravatar_id": "",
81
+ "url": "https://api.github.com/users/octocat",
82
+ "html_url": "https://github.com/octocat",
83
+ "followers_url": "https://api.github.com/users/octocat/followers",
84
+ "following_url": "https://api.github.com/users/octocat/following{/other_user}",
85
+ "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
86
+ "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
87
+ "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
88
+ "organizations_url": "https://api.github.com/users/octocat/orgs",
89
+ "repos_url": "https://api.github.com/users/octocat/repos",
90
+ "events_url": "https://api.github.com/users/octocat/events{/privacy}",
91
+ "received_events_url": "https://api.github.com/users/octocat/received_events",
92
+ "type": "User",
93
+ "site_admin": false
94
+ },
95
+ "change_status": {
96
+ "deletions": 0,
97
+ "additions": 180,
98
+ "total": 180
99
+ },
100
+ "committed_at": "2010-04-14T02:15:15Z"
101
+ }
102
+ ]
103
+ }
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+ require 'json'
3
+
4
+ describe Woro::Adapters::Gist do
5
+
6
+ let!(:gist_id) { rand(999)}
7
+ let(:task) { Woro::Task.new('create_user') }
8
+ subject { Woro::Adapters::Gist.new(gist_id) }
9
+ let(:gist_hash) do
10
+ FakeFS.deactivate!
11
+ body = File.read(File.join('spec', 'fixtures', 'gist.json'))
12
+ FakeFS.activate!
13
+ JSON.parse(body)
14
+ end
15
+
16
+ before do
17
+ allow(subject).to receive(:gist).once.and_return gist_hash
18
+ end
19
+
20
+ describe '#list_keys' do
21
+ it 'returns list' do
22
+ expected_list = {
23
+ "create_user.rake" => {
24
+ "size"=>932, "raw_url"=>"https://gist.githubusercontent.com/raw/365370/8c4d2d43d178df44f4c03a7f2ac0ff512853564e/ring.erl", "type"=>"text/plain", "language"=>"Ruby", "truncated"=>false, "content"=>"namespace :woro do\n desc 'Create User'\n task create_user: :environment do\n # Code\n end\nend\n"
25
+ }
26
+ }
27
+ expect(subject.list_keys).to eq expected_list
28
+ end
29
+ end
30
+
31
+ describe '#push' do
32
+ it 'calls gist services with correct params' do
33
+ File.open(task.file_path, 'w') do |f|
34
+ f.puts 'hey'
35
+ end
36
+ expected_files_hash = { task.file_name => task.read_task_file }
37
+ expected_params_hash = { public: false,
38
+ update: gist_id,
39
+ output: :all
40
+ }
41
+ expect(Gist).to receive(:multi_gist).with(expected_files_hash, expected_params_hash).and_return gist_hash
42
+ subject.push(task)
43
+ end
44
+ end
45
+
46
+
47
+ describe '#retrieve_file_data' do
48
+ it 'returns data hash from file' do
49
+ expected_hash = {
50
+ "size"=>932, "raw_url"=>"https://gist.githubusercontent.com/raw/365370/8c4d2d43d178df44f4c03a7f2ac0ff512853564e/ring.erl", "type"=>"text/plain", "language"=>"Ruby", "truncated"=>false, "content"=>"namespace :woro do\n desc 'Create User'\n task create_user: :environment do\n # Code\n end\nend\n"
51
+ }
52
+ expect(subject.retrieve_file_data('create_user.rake')).to eq expected_hash
53
+ end
54
+ end
55
+
56
+ describe '#raw_url' do
57
+ it 'returns raw_url of file' do
58
+ expected_url = "https://gist.githubusercontent.com/raw/365370/8c4d2d43d178df44f4c03a7f2ac0ff512853564e/ring.erl"
59
+ expect(subject.raw_url('create_user.rake')).to eq expected_url
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+
3
+ describe Woro::Configuration do
4
+
5
+ describe '#initialize' do
6
+ it 'instantiates object' do
7
+ options = {
8
+ adapters: %(foo baz),
9
+ app_name: 'bar'
10
+ }
11
+ config = Woro::Configuration.new(options)
12
+ expect(config.adapters).to eq %(foo baz)
13
+ expect(config.app_name).to eq 'bar'
14
+ end
15
+ end
16
+
17
+ describe '.load' do
18
+ context 'not given a configuration file' do
19
+ it 'returns Configuration object with default options' do
20
+ config = Woro::Configuration.load
21
+ expect(config.adapters).to be_falsy
22
+ expect(config.app_name).to be_falsy
23
+ end
24
+
25
+ it 'writes a configuration file with default options' do
26
+ Woro::Configuration.load
27
+ expect(File.read(Woro::Configuration.config_file)).to eq \
28
+ YAML.dump(Woro::Configuration.default_options)
29
+ end
30
+ end
31
+
32
+ context 'given a configuration file' do
33
+ before(:each) do
34
+ opts = {
35
+ adapters: %w(foo baz),
36
+ app_name: 'bar'
37
+ }
38
+ File.open(Woro::Configuration.config_file, 'w') do |file|
39
+ YAML.dump(opts, file)
40
+ end
41
+ end
42
+
43
+ it 'returns Configuration object with options in file' do
44
+ config = Woro::Configuration.load
45
+ expect(config.adapters).to eq %w(foo baz)
46
+ expect(config.app_name).to eq 'bar'
47
+ end
48
+
49
+ context 'given options' do
50
+ it 'overrides options in configuration file' do
51
+ options = {
52
+ adapters: %w(goo grr),
53
+ app_name: 'car'
54
+ }
55
+ config = Woro::Configuration.load(options)
56
+ expect(config.adapters).to eq %w(goo grr)
57
+ expect(config.app_name).to eq 'car'
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ describe '.save' do
64
+ let(:options) do
65
+ {
66
+ adapters: ['foo', 'baz'],
67
+ app_name: 'bar'
68
+ }
69
+ end
70
+
71
+ context 'not given a configuration file' do
72
+ it 'writes a configuration file with options' do
73
+ Woro::Configuration.save(options)
74
+ expect(File.read(Woro::Configuration.config_file)).to eq \
75
+ YAML.dump(options)
76
+ end
77
+ end
78
+
79
+ context 'given a configuration file' do
80
+ before(:each) do
81
+ opts = {
82
+ adapters: ['goo', 'grr'],
83
+ app_name: 'car'
84
+ }
85
+ File.open(Woro::Configuration.config_file, 'w') do |file|
86
+ YAML.dump(opts, file)
87
+ end
88
+ end
89
+
90
+ it 'does not overwrite' do
91
+ Woro::Configuration.save(options)
92
+ expect(File.read(Woro::Configuration.config_file)).to_not eq \
93
+ YAML.dump(options)
94
+ end
95
+
96
+ it 'does overwrite if passed `force` option' do
97
+ Woro::Configuration.save(options.merge(:force => true))
98
+ expect(File.read(Woro::Configuration.config_file)).to eq \
99
+ YAML.dump(options)
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Woro::Task do
4
+
5
+ subject { Woro::Task.new('cleanup_task') }
6
+
7
+ describe '#create_from_task_template' do
8
+ it 'creates new file' do
9
+ FakeFS.deactivate!
10
+ example_path = File.join('spec', 'fixtures','fresh_template.yml')
11
+ fresh_template_body = File.read example_path
12
+ FakeFS.activate!
13
+ subject.create_from_task_template
14
+ expect(File.read(Woro::Task.file_path)).to eq fresh_template_body
15
+ end
16
+ end
17
+
18
+ describe '#file_name' do
19
+ context 'taskname is cleanup_task' do
20
+ it 'returns cleanup_task.rake' do
21
+ expect(subject.file_name).to eq 'cleanup_task.rake'
22
+ end
23
+ end
24
+ end
25
+
26
+ describe '#file_path' do
27
+ context 'task path is lib/woro_tasks/cleanup_task' do
28
+ it 'returns lib/woro_tasks/cleanup_task.rake' do
29
+ expect(subject.file_path).to eq 'lib/woro_tasks/cleanup_task.rake'
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ require 'pry'
2
+ require 'woro'
3
+ require 'fakefs/safe'
4
+ require 'aws-sdk-v1'
5
+
6
+ Dir[('./spec/support/**/*.rb')].each {|f| require f}
7
+
8
+ RSpec.configure do |config|
9
+ config.color = true
10
+ config.order = 'random'
11
+
12
+ config.before(:each) do
13
+ FakeFS.activate!
14
+ FileUtils.mkdir_p 'config'
15
+ FileUtils.mkdir_p 'lib/woro_tasks'
16
+ FileUtils.mkdir_p 'lib/tasks'
17
+ end
18
+
19
+ config.after(:each) do
20
+ FakeFS.deactivate!
21
+ FakeFS::FileSystem.clear
22
+ end
23
+
24
+ end
25
+
data/woro.gemspec CHANGED
@@ -23,8 +23,6 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_development_dependency "bundler", "~> 1.7"
25
25
  spec.add_development_dependency "rake", "~> 10.0"
26
- spec.add_development_dependency "rspec"
27
- spec.add_development_dependency "rspec-nc"
28
26
  spec.add_development_dependency "guard"
29
27
  spec.add_development_dependency "guard-rspec"
30
28
  spec.add_development_dependency "pry"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: woro
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Senff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-27 00:00:00.000000000 Z
11
+ date: 2015-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gist
@@ -66,34 +66,6 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '10.0'
69
- - !ruby/object:Gem::Dependency
70
- name: rspec
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rspec-nc
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
69
  - !ruby/object:Gem::Dependency
98
70
  name: guard
99
71
  requirement: !ruby/object:Gem::Requirement
@@ -192,16 +164,24 @@ files:
192
164
  - README.md
193
165
  - Rakefile
194
166
  - bin/woro
167
+ - lib/capistrano/woro.rb
195
168
  - lib/mina/woro.rb
196
169
  - lib/woro.rb
170
+ - lib/woro/adapters/gist.rb
197
171
  - lib/woro/configuration.rb
198
- - lib/woro/gister.rb
199
172
  - lib/woro/task.rb
173
+ - lib/woro/task_helper.rb
200
174
  - lib/woro/tasks/capistrano.rake
201
175
  - lib/woro/tasks/mina.rake
202
176
  - lib/woro/templates/task.rake
203
177
  - lib/woro/templates/woro.rake
204
178
  - lib/woro/version.rb
179
+ - spec/fixtures/fresh_template.yml
180
+ - spec/fixtures/gist.json
181
+ - spec/lib/woro/adapters/gist_spec.rb
182
+ - spec/lib/woro/configuration_spec.rb
183
+ - spec/lib/woro/task_spec.rb
184
+ - spec/spec_helper.rb
205
185
  - woro.gemspec
206
186
  homepage: http://github.com/Dahie/woro
207
187
  licenses:
@@ -228,4 +208,10 @@ signing_key:
228
208
  specification_version: 4
229
209
  summary: Write once, run once. One-time migration task management on remote servers
230
210
  through mina.
231
- test_files: []
211
+ test_files:
212
+ - spec/fixtures/fresh_template.yml
213
+ - spec/fixtures/gist.json
214
+ - spec/lib/woro/adapters/gist_spec.rb
215
+ - spec/lib/woro/configuration_spec.rb
216
+ - spec/lib/woro/task_spec.rb
217
+ - spec/spec_helper.rb
data/lib/woro/gister.rb DELETED
@@ -1,45 +0,0 @@
1
- require 'gist'
2
- require 'net/https'
3
-
4
- # All classes and modules specific to Woro.
5
- module Woro
6
- # Various shared static helpers
7
- class Gister
8
- class << self
9
- # Creates an initial welcome gist on project setup
10
- # @param app_name [String] Name of the app is displayed in the initial welcome message
11
- def create_initial_gist(app_name, access_token=nil)
12
- Gist.gist("Welcome to the Woro Task Repository for #{app_name}", filename: app_name, access_token: access_token)
13
- end
14
-
15
- # Retrieves metadata of the specified gist
16
- # @param gist_id [String] id of the gist
17
- # @return [Hash] parsed JSON hash
18
- def retrieve_gist(gist_id)
19
- service_url = "https://api.github.com/gists/#{gist_id}"
20
- response = Net::HTTP.get_response(URI.parse(service_url))
21
- JSON.parse(response.body)
22
- end
23
-
24
- # Extract description from gist's data content string.
25
- # @param data [Hash] gist data hash
26
- # [String] description string
27
- def extract_description(data)
28
- data['content'].match(/desc ['"]([a-zA-Z0-9\s]*)['"]/)[1]
29
- end
30
-
31
- # Returns the list of files included in the specified gist
32
- # @param gist_id [String] id of the gist
33
- # @return [Hash] List of files in the format { filename: { data }}
34
- def get_list_of_files(gist_id)
35
- retrieve_gist(gist_id)['files']
36
- end
37
-
38
- # Read the rake task template
39
- # @return [String]
40
- def read_template_file
41
- File.read(File.dirname(__FILE__) + '/templates/task.rake')
42
- end
43
- end
44
- end
45
- end