flash 0.0.3 → 0.1.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.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZTEyMWQwMmZmMzU5ZTVmODE0MzJlYjIxNjI1ZmU4NzgwYTNiNGFiNw==
5
+ data.tar.gz: !binary |-
6
+ MDVjYTBkN2Q2ZGM4M2M5ZWU2YmNiMjg5NTAyZDczNDY1MzgxMzdiYQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ OTk4ZjJkZDExZjYxYjI5Y2MzMmFhMDJkODRlMTYxYjkxMDY1NTQzZjUxYTgz
10
+ ODJmNjM1MmZhMGFiMzI3YWQ2MzkzM2MyM2QxZWMwZjBjNjFiNzA0MjY3YjZh
11
+ N2M2YjkyMDA1NzEyZWNlMDY4N2Q0YzUwMjQ4ZTYyY2FlMGQzMTY=
12
+ data.tar.gz: !binary |-
13
+ NzhkZWE3Y2NkYjE5OWZmMTkzODhmNjVmMzI5MDYwNzczZTQzMjQwZGQ2Yjgz
14
+ YmRiZWM4N2ZiMTg3ZWU4Y2M2NzI0ZDAyYzI2NTYyODlkYmQ1MGNiYzM3YmRm
15
+ ZDFlNTVjMTcxZDQwMGQ2MWI1NzBiNzJiOTZlY2ZkYjkzNDE0NDc=
data/README.md CHANGED
@@ -1,40 +1,195 @@
1
- # Flash
1
+ Flash
2
+ =====
2
3
 
3
- Flash helps you run arbitrary or predefined commands on multiple projects all defined in the Runfile.
4
+ [![Gem Version](https://badge.fury.io/rb/flash.svg)](http://badge.fury.io/rb/flash)
5
+ [![Build Status](https://travis-ci.org/colmarius/flash.svg?branch=master)](https://travis-ci.org/colmarius/flash?branch=master)
4
6
 
5
- # Installation
7
+ ![flash](http://colmarius.net/flash/images/flashtocat.png)
8
+
9
+ Overview
10
+ --------
11
+
12
+ Main purpose of Flash is to eliminate repetitive tasks, those of running the
13
+ same commands on multiple directories.
14
+
15
+ It allows one to define:
16
+ - __aliases__ for sets of commands to be run on multiple directories
17
+ - __groups__ for grouping together multiple directories
18
+
19
+ Both groups and aliases can be defined in the `.flash.yml` configuration file.
20
+
21
+ Motivation
22
+ ----------
23
+
24
+ __Simple configuration file__
25
+
26
+ A place to define both groups and aliases.
27
+
28
+ __Inspect output__
29
+
30
+ See the output of flash commands runned on a group of projects.
31
+
32
+ Installation
33
+ ------------
34
+
35
+ You can either install the gem manually:
6
36
 
7
37
  ```bash
8
- > gem install flash
38
+ gem install flash
9
39
  ```
10
40
 
11
- The command available is run:
41
+ or add it to your Gemfile:
12
42
 
13
- ```bash
14
- > run
15
- Group name is missing.
16
- Usage: run [options] group
17
- -c, --command command Commands to run (semicolon separated)
18
- -d, --debug Debug: print each command result
19
- -r, --recipe recipe Run registered recipe if present
20
- -l, --list-recipes List registered recipes
21
- -h, --help Help documentation
43
+ ```ruby
44
+ group :development do
45
+ gem 'flash'
46
+ end
22
47
  ```
23
48
 
24
- # Example
49
+ Usage
50
+ -----
25
51
 
26
- ```bash
27
- > cd example
28
- > run -c ls projects
29
- salsa> ls
30
- cubana
52
+ Flash requires a `.flash.yml` file in order to function. This should be
53
+ defined at the root of your workspace folder.
54
+
55
+ ```
56
+ # .flash.yml
31
57
 
32
- dancing> ls
33
- bouncing
58
+ frontend:
59
+ - super-product1
60
+ - super-product2
61
+ - super-api
62
+ - super-sso
34
63
 
35
- school> ls
36
- fun
64
+ libraries:
65
+ - super-rest-client
66
+ - super-core-js
67
+ - super-core-css
37
68
 
69
+ aliases:
70
+ update-master: git stash; git checkout master; git pull
71
+ status: git status -s
72
+
73
+ clone:
74
+ git: git@github.com:SuperDuper
38
75
  ```
39
76
 
40
- TODO: write detailed description
77
+ Here we define two groups _frontend_ and _libraries_. We will be allowed to run commands on each of these groups.
78
+
79
+ We can also define two special configuration sections:
80
+
81
+ - __aliases__: allows us two save repetitive and long commands
82
+ - __clone__: allows to define a base __git__ URL from where projects in a group can be cloned
83
+
84
+ With a valid `.flash.yml` configuration file set in your current workspace you
85
+ are now set to run flash commands.
86
+
87
+ Commands
88
+ --------
89
+
90
+ Running `flash` will give you the following output:
91
+
92
+ Commands:
93
+ flash clone GROUP # Clone all projects found in GROUP config file
94
+ flash help [COMMAND] # Describe available commands or one specific command
95
+ flash info [GROUP] # Display information from config file
96
+ flash run COMMAND GROUP # Run one or more COMMAND(s) on the specified GROUP
97
+ flash version # Display Flash gem version
98
+
99
+ ### flash clone
100
+
101
+ flash clone GROUP
102
+
103
+ Allows to clone all projects defined in a GROUP by using the clone git base
104
+ URL.
105
+
106
+ Getting back to our `.flash.yml` example file...
107
+
108
+ ```
109
+ # .flash.yml
110
+
111
+ frontend:
112
+ - super-product1
113
+ - super-product2
114
+ - super-api
115
+ - super-sso
116
+
117
+ ...
118
+
119
+ clone:
120
+ git: git@github.com:SuperDuper
121
+ ```
122
+
123
+ Running the following command...
124
+
125
+ flash clone frontend
126
+
127
+ will clone from SuperDuper organization all projects defined in _frontend_
128
+ group.
129
+
130
+ ### flash info
131
+
132
+ flash info [GROUP]
133
+
134
+ This is a helper command for printing `.flash.yml` contents. Prints all file
135
+ contents or just part of it (depending if group or other config section is
136
+ specified).
137
+
138
+ ### flash run
139
+
140
+ flash run COMMAND GROUP
141
+
142
+ The heart of flash is the __run__ command. It requires both a COMMAND and a
143
+ GROUP. With this command one can run same tasks on all projects of same GROUP.
144
+
145
+ Note: COMMAND can be a standalone command, or be defined in `aliases` section
146
+ (where it must be a list of commands, semi-column separated).
147
+
148
+ Getting back to our `.flash.yml` example file...
149
+
150
+ ```
151
+ # .flash.yml
152
+
153
+ frontend:
154
+ - super-product1
155
+ - super-product2
156
+ - super-api
157
+ - super-sso
158
+
159
+ libraries:
160
+ - super-rest-client
161
+ - super-core-js
162
+ - super-core-css
163
+
164
+ aliases:
165
+ update-master: git stash; git checkout master; git pull
166
+ status: git status -s
167
+ ```
168
+
169
+ here are some commands you can run:
170
+
171
+ # Update master branch.
172
+ flash run update-master frontend
173
+ flash run update-master libraries
174
+
175
+ # Display status.
176
+ flash run status frontend
177
+
178
+ # List some files.
179
+ flash run ls frontend
180
+
181
+ # Lets push master branch to origin/staging (forced) for all frontend projects.
182
+ flash run "git checkout master ; git checkout -B staging ; git push -f ; git checkout master" frontend
183
+
184
+ # This last command could be aliased to `master-to-staging`, which would result in:
185
+ flash run master-to-staging frontend
186
+
187
+ Contributing
188
+ ------------
189
+
190
+ Please see [CONTRIBUTING.md](https://github.com/colmarius/flash/blob/master/CONTRIBUTING.md).
191
+
192
+ Note
193
+ ----
194
+
195
+ This is a project to level up my gem skills.
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'flash/cli'
6
+
7
+ Flash::CLI.start
@@ -0,0 +1,50 @@
1
+ require 'flash'
2
+ require 'flash/command/clone'
3
+ require 'flash/command/info'
4
+ require 'flash/command/run'
5
+ require 'thor'
6
+
7
+ class Flash::CLI < Thor
8
+ class << self
9
+ def is_thor_reserved_word?(word, type)
10
+ return false if word == 'run'
11
+ super
12
+ end
13
+ end
14
+
15
+ desc 'clone GROUP', 'Clone all projects found in GROUP config file'
16
+
17
+ def clone(group)
18
+ Flash::Command::Clone.new(group).execute
19
+ end
20
+
21
+ desc 'info [GROUP]', 'Display information from config file'
22
+
23
+ def info(group = nil)
24
+ Flash::Command::Info.new(group).execute
25
+ end
26
+
27
+ desc 'run COMMAND GROUP', 'Run one or more COMMAND(s) on the specified GROUP'
28
+
29
+ long_desc <<-LONGDESC
30
+ Run the COMMAND(s) on the specified GROUP.
31
+
32
+ More than one command can be specified if wrapped under quotes
33
+ and are semi-column separated.
34
+
35
+ In alternative aliases can be used, which can be defined under "aliases"
36
+ in .flash.yml config file.
37
+ LONGDESC
38
+
39
+ def run(command, group)
40
+ Flash::Command::Run.new(command, group).execute
41
+ end
42
+
43
+ desc 'version', 'Display Flash gem version'
44
+
45
+ map ['-v', '--version'] => :version
46
+
47
+ def version
48
+ puts Flash::VERSION
49
+ end
50
+ end
@@ -0,0 +1,4 @@
1
+ require 'flash'
2
+
3
+ module Flash::Command
4
+ end
@@ -0,0 +1,16 @@
1
+ require 'flash'
2
+ require 'flash/command'
3
+ require 'flash/config'
4
+
5
+ class Flash::Command::Base
6
+ def initialize
7
+ end
8
+
9
+ def config
10
+ @config ||= Flash::Config.new
11
+ end
12
+
13
+ def valid_group?(group)
14
+ (group && config[group]) ? true : false
15
+ end
16
+ end
@@ -0,0 +1,57 @@
1
+ require 'flash'
2
+ require 'flash/command/base'
3
+
4
+ class Flash::Command::Clone < Flash::Command::Base
5
+ def initialize(group)
6
+ @group = group
7
+ end
8
+
9
+ def execute
10
+ raise(ArgumentError, 'Missing required group parameter.') unless @group
11
+
12
+ unknown_group_and_exit(@group) unless valid_group?(@group)
13
+ missing_git_clone_url unless has_clone_git_url?
14
+ clone_projects(@group)
15
+ end
16
+
17
+ private
18
+
19
+ def unknown_group_and_exit(group)
20
+ puts "Unknown group \"#{group}\" in .flash.yml config."
21
+ exit 1
22
+ end
23
+
24
+ def missing_git_clone_url
25
+ puts 'Missing clone git URL defined in .flash.yml config.'
26
+ exit 1
27
+ end
28
+
29
+ def has_clone_git_url?
30
+ clone_git_url = (config['clone'] && config['clone']['git'])
31
+ clone_git_url ? true : false
32
+ end
33
+
34
+ def clone_projects(group)
35
+ projects(group).each do |project|
36
+ clone_single(project) unless File.exist?(project)
37
+ puts "\n[#{project}] Done cloning project.\n\n"
38
+ end
39
+ end
40
+
41
+ def projects(group)
42
+ config[group] || []
43
+ end
44
+
45
+ def clone_single(project)
46
+ system('git', 'clone', clone_path(project))
47
+ end
48
+
49
+ def clone_path(project)
50
+ "#{ base_clone_path }/#{ project }.git"
51
+ end
52
+
53
+ def base_clone_path
54
+ base_url = config['clone']['git']
55
+ base_url.gsub(/\/+$/, '')
56
+ end
57
+ end
@@ -0,0 +1,25 @@
1
+ require 'flash'
2
+ require 'flash/command/base'
3
+
4
+ class Flash::Command::Info < Flash::Command::Base
5
+ def initialize(group = nil)
6
+ @group = group
7
+ end
8
+
9
+ def execute
10
+ puts output(@group)
11
+ end
12
+
13
+ private
14
+
15
+ def output(group = nil)
16
+ return unknown_group(group) if group && !valid_group?(group)
17
+
18
+ result = valid_group?(group) ? config[group] : config
19
+ result.to_yaml
20
+ end
21
+
22
+ def unknown_group(group)
23
+ "Unknown group \"#{group}\" in .flash.yml config."
24
+ end
25
+ end
@@ -0,0 +1,78 @@
1
+ require 'flash'
2
+ require 'flash/command/base'
3
+ require 'pathname'
4
+
5
+ class Flash::Command::Run < Flash::Command::Base
6
+ def initialize(command, group)
7
+ @command = command
8
+ @group = group
9
+ end
10
+
11
+ def execute
12
+ raise(ArgumentError, 'Missing required command and group parameters.') unless @command && @group
13
+
14
+ unknown_group_and_exit(@group) unless valid_group?(@group)
15
+ run_command_in_group(@command, @group)
16
+ end
17
+
18
+ private
19
+
20
+ def unknown_group_and_exit(group)
21
+ puts "Unknown group \"#{group}\" in .flash.yml config."
22
+ exit 1
23
+ end
24
+
25
+ def run_command_in_group(command, group)
26
+ projects(group).each do |project|
27
+ color = new_color
28
+
29
+ system("cd #{ project_dir(project) }")
30
+ commands(command).each { |cmd| run(cmd, color: color, project: project) }
31
+
32
+ say('', color)
33
+ end
34
+ end
35
+
36
+ def projects(group)
37
+ config[group]
38
+ end
39
+
40
+ def run(command, options = {})
41
+ verbose = options[:verbose].nil? ? true : options[:verbose]
42
+ color = options[:color]
43
+ project = options[:project]
44
+
45
+ prompt(command, color: color, project: project) if verbose
46
+ system("cd #{ project_dir(project) } ; #{ command }")
47
+ end
48
+
49
+ def commands(alias_or_command)
50
+ commands = aliases[alias_or_command] || alias_or_command
51
+ commands.split(';').map(&:strip)
52
+ end
53
+
54
+ def aliases
55
+ config['aliases'] || {}
56
+ end
57
+
58
+ def prompt(message, options)
59
+ color = options[:color]
60
+ project = options[:project]
61
+
62
+ say("#{ project }> #{ message }", color)
63
+ end
64
+
65
+ def say(stuff, color)
66
+ prefix = "\e[38;5;#{ color }m"
67
+ suffix = "\e[0m"
68
+ system "echo '#{ prefix }#{ stuff }#{ suffix }'"
69
+ end
70
+
71
+ def new_color
72
+ rand((1..22)) * 10 + 2
73
+ end
74
+
75
+ def project_dir(project)
76
+ "#{ Dir.pwd }/#{ project }"
77
+ end
78
+ end
@@ -0,0 +1,26 @@
1
+ require 'flash'
2
+ require 'yaml'
3
+ require 'delegate'
4
+
5
+ class Flash::Config < SimpleDelegator
6
+ def initialize
7
+ check_config_file!
8
+ data = YAML.load_file(config_file)
9
+ super(data)
10
+ end
11
+
12
+ private
13
+
14
+ def check_config_file!
15
+ error("#{config_file} does not exist.") unless File.exist?(config_file)
16
+ end
17
+
18
+ def config_file
19
+ '.flash.yml'
20
+ end
21
+
22
+ def error(message)
23
+ puts "ERROR: #{message}"
24
+ exit 1
25
+ end
26
+ end
@@ -1,3 +1,3 @@
1
1
  module Flash
2
- VERSION = '0.0.3'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+ require 'flash/cli'
3
+
4
+ describe Flash::CLI, :fakefs do
5
+ subject { described_class }
6
+
7
+ describe '.is_thor_reserved_word?' do
8
+ it 'should allow "run" to be defined as command' do
9
+ expect(subject.is_thor_reserved_word?('run', :command)).to be_falsey
10
+ end
11
+ end
12
+
13
+ describe '#clone' do
14
+ before { write_config_file_with_clone }
15
+
16
+ describe 'flash clone projects' do
17
+ let(:output) { flash('clone projects') }
18
+
19
+ it 'should show done cloning messages' do
20
+ expect_any_instance_of(Flash::Command::Clone)
21
+ .to receive(:system).exactly(3).times.and_return(nil)
22
+
23
+ expect(output).to match(/\[foo\] Done cloning project\./)
24
+ expect(output).to match(/\[bar\] Done cloning project\./)
25
+ expect(output).to match(/\[buz\] Done cloning project\./)
26
+ end
27
+ end
28
+ end
29
+
30
+ describe '#info' do
31
+ before { write_config_file }
32
+
33
+ describe 'flash info' do
34
+ let(:output) { flash('info') }
35
+
36
+ it 'should print all info from config file' do
37
+ expect(output).to match(/projects/)
38
+ expect(output).to match(/foo/)
39
+ expect(output).to match(/bar/)
40
+ expect(output).to match(/buz/)
41
+ expect(output).to match(/libraries/)
42
+ expect(output).to match(/cippa/)
43
+ expect(output).to match(/lippa/)
44
+ end
45
+ end
46
+
47
+ describe 'flash info projects' do
48
+ let(:output) { flash('info projects') }
49
+
50
+ it 'should print info from config file for "projects" group' do
51
+ expect(output).to match(/foo/)
52
+ expect(output).to match(/bar/)
53
+ expect(output).to match(/buz/)
54
+ end
55
+ end
56
+
57
+ describe 'flash info blabla' do
58
+ let(:output) { flash('info blabla') }
59
+
60
+ it 'should print unknown group' do
61
+ expect(output).to match(/Unknown group "blabla" in .flash.yml config.\n/)
62
+ end
63
+ end
64
+ end
65
+
66
+ describe '#run' do
67
+ before { write_config_file }
68
+
69
+ describe 'flash run ls projects' do
70
+ let(:output) { flash('run ls projects') }
71
+
72
+ it 'should not raise error' do
73
+ expect_any_instance_of(Flash::Command::Run)
74
+ .to receive(:system).exactly(12).times
75
+
76
+ output
77
+ end
78
+ end
79
+ end
80
+
81
+ describe '#version' do
82
+ let(:output) { flash('version') }
83
+
84
+ it 'should print version number' do
85
+ expect(output).to match(/#{Flash::VERSION}\n/)
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ require 'flash/command/base'
3
+
4
+ describe Flash::Command::Base, :fakefs do
5
+ subject { described_class.new }
6
+
7
+ before { write_config_file }
8
+
9
+ describe '#config' do
10
+ let(:config) { subject.config }
11
+
12
+ it 'should be of correct kind' do
13
+ expect(config).to be_an_instance_of(Flash::Config)
14
+ end
15
+
16
+ it 'should behave as Hash' do
17
+ expect(config).to respond_to(:[])
18
+ end
19
+ end
20
+
21
+ describe '#valid_group?' do
22
+ it 'responds true for valid groups' do
23
+ expect(subject.valid_group?('projects')).to be_truthy
24
+ expect(subject.valid_group?('libraries')).to be_truthy
25
+ end
26
+
27
+ it 'responds false otherwise' do
28
+ expect(subject.valid_group?('unknkown')).to be_falsey
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ require 'flash/command/clone'
3
+
4
+ describe Flash::Command::Clone, :fakefs do
5
+ subject { described_class.new(@group) }
6
+
7
+ before { write_config_file }
8
+
9
+ describe '#execute' do
10
+
11
+ context 'with invalid group' do
12
+ it 'with nil group' do
13
+ @group = nil
14
+ expect { subject.execute }.to raise_error ArgumentError
15
+ end
16
+
17
+ it 'with empty group' do
18
+ @group = ''
19
+ output = capture_stdout do
20
+ expect { subject.execute }.to raise_error SystemExit
21
+ end
22
+ expect(output).to match(/Unknown group "" in .flash.yml config./)
23
+ end
24
+
25
+ it 'with unknown group' do
26
+ @group = 'unknown'
27
+ output = capture_stdout do
28
+ expect { subject.execute }.to raise_error SystemExit
29
+ end
30
+ expect(output).to match(/Unknown group "unknown" in .flash.yml config./)
31
+ end
32
+ end
33
+
34
+ context 'with valid group' do
35
+ before { @group = 'projects' }
36
+
37
+ describe 'without clone git endpoint' do
38
+ it 'should raise error' do
39
+ output = capture_stdout do
40
+ expect { subject.execute }.to raise_error SystemExit
41
+ end
42
+ expect(output).to match(/Missing clone git URL defined in .flash.yml config./)
43
+ end
44
+ end
45
+
46
+ describe 'with clone git endpoint' do
47
+ before { write_config_file_with_clone }
48
+
49
+ it 'should clone projects in group' do
50
+ expect(subject).to receive(:clone_projects).with(@group).once
51
+ subject.execute
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+ require 'flash/command/info'
3
+
4
+ describe Flash::Command::Info, :fakefs do
5
+ subject { described_class.new(group) }
6
+
7
+ before { write_config_file }
8
+
9
+ describe '#execute' do
10
+ let(:group) { 'projects' }
11
+
12
+ it 'calls output method with group' do
13
+ expect(subject).to receive(:output).with(group).once
14
+ subject.execute
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+ require 'flash/command/run'
3
+
4
+ describe Flash::Command::Run, :fakefs do
5
+ subject { described_class.new(@command, @group) }
6
+
7
+ before { write_config_file }
8
+
9
+ describe '#execute' do
10
+
11
+ context 'with invalid args' do
12
+
13
+ it 'command and group are nil' do
14
+ @command, @group = [nil, nil]
15
+ expect { subject.execute }.to raise_error ArgumentError
16
+ end
17
+
18
+ it 'command and group are empty strings' do
19
+ @command, @group = ['', '']
20
+ output = capture_stdout do
21
+ expect { subject.execute }.to raise_error SystemExit
22
+ end
23
+ expect(output).to match(/Unknown group "" in \.flash\.yml config\./)
24
+ end
25
+
26
+ it 'unknown group' do
27
+ @command = ''
28
+ @group = 'unknown'
29
+ output = capture_stdout do
30
+ expect { subject.execute }.to raise_error SystemExit
31
+ end
32
+ expect(output).to match(/Unknown group "unknown" in \.flash\.yml config\./)
33
+ end
34
+ end
35
+
36
+ context 'with valid args' do
37
+
38
+ it 'example run ls command on projects group' do
39
+ @command = 'ls'
40
+ @group = 'projects'
41
+ expect_any_instance_of(described_class)
42
+ .to receive(:system).exactly(12).times
43
+ subject.execute
44
+ end
45
+
46
+ it 'calls run command in group once' do
47
+ @command = 'ls'
48
+ @group = 'projects'
49
+ expect_any_instance_of(described_class)
50
+ .to receive(:run_command_in_group).with(@command, @group).once
51
+ subject.execute
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ require 'flash/config'
3
+
4
+ describe Flash::Config, :fakefs do
5
+ subject { described_class.new }
6
+
7
+ describe '#initialize' do
8
+ it 'can load from a file' do
9
+ write_config_file
10
+ expect(subject['projects']).to eq %w(foo bar buz)
11
+ end
12
+
13
+ it 'will exit with error message if no config file found' do
14
+ output = capture_stdout do
15
+ expect { subject }.to raise_error SystemExit
16
+ end
17
+ expect(output).to match(/ERROR: .flash.yml does not exist.\n/)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+ require 'flash'
3
+
4
+ describe Flash do
5
+
6
+ describe '#version' do
7
+ subject { Flash::VERSION }
8
+ it { should be_a String }
9
+ end
10
+ end
@@ -1,7 +1,84 @@
1
- require 'rspec/autorun'
1
+ if ENV['TRAVIS'] || ENV['COVERAGE']
2
+ require 'simplecov'
3
+
4
+ if ENV['TRAVIS']
5
+ require 'coveralls'
6
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
7
+ end
8
+
9
+ SimpleCov.start do
10
+ add_filter '/spec'
11
+ add_filter '/vendor'
12
+ end
13
+ end
14
+
15
+ require 'rspec'
16
+ require 'fakefs/safe'
17
+ require 'fakefs/spec_helpers'
18
+
19
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
20
 
3
21
  RSpec.configure do |config|
4
- config.expect_with :rspec do |c|
5
- c.syntax = :expect
22
+ config.color = true
23
+ config.order = 'rand'
24
+ config.raise_errors_for_deprecations!
25
+ config.include FakeFS::SpecHelpers, :fakefs
26
+ end
27
+
28
+ def flash(args)
29
+ capture_stdout do
30
+ begin
31
+ Flash::CLI.start(args.split(' '))
32
+ rescue SystemExit
33
+ nil
34
+ end
35
+ end
36
+ end
37
+
38
+ def write_config_file_with_clone
39
+ clone_contents = <<-SECTION
40
+ clone:
41
+ git: git@github.com:SuperDuper
42
+ SECTION
43
+
44
+ write_config_file(contents: default_contents + clone_contents)
45
+ end
46
+
47
+ def write_config_file(options = {})
48
+ config_file = options[:config_file] || '.flash.yml'
49
+ contents = options[:contents] || default_contents
50
+
51
+ File.open(config_file, 'w') do |file|
52
+ contents.split('\n').each do |line|
53
+ file.puts line
54
+ end
6
55
  end
56
+ File.expand_path(config_file)
57
+ end
58
+
59
+ def default_contents
60
+ <<-CONTENTS
61
+ projects:
62
+ - foo
63
+ - bar
64
+ - buz
65
+ libraries:
66
+ - cippa
67
+ - lippa
68
+ CONTENTS
69
+ end
70
+
71
+ def make_pipe
72
+ IO.method(:pipe).arity.zero? ? IO.pipe : IO.pipe('BINARY')
73
+ end
74
+
75
+ def capture_stdout
76
+ old_stdout = $stdout.dup
77
+ rd, wr = make_pipe
78
+ $stdout = wr
79
+ yield
80
+ wr.close
81
+ rd.read
82
+ ensure
83
+ $stdout = old_stdout
7
84
  end
metadata CHANGED
@@ -1,70 +1,80 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flash
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
5
- prerelease:
4
+ version: 0.1.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Marius Colacioiu
9
8
  autorequire:
10
- bindir: bin
9
+ bindir: exe
11
10
  cert_chain: []
12
- date: 2014-01-03 00:00:00.000000000 Z
13
- dependencies: []
14
- description: Flash helps you run commands on multiple projects all defined in the
15
- Runfile
11
+ date: 2014-08-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.19.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.19.1
27
+ description: Flash helps you run same commands on multiple projects all defined in
28
+ the `.flash.yml` config.
16
29
  email:
17
30
  - marius.colacioiu@gmail.com
18
31
  executables:
19
- - run
32
+ - flash
20
33
  extensions: []
21
34
  extra_rdoc_files: []
22
35
  files:
23
- - .gitignore
24
- - Gemfile
25
- - Gemfile.lock
26
36
  - README.md
27
- - Rakefile
28
- - bin/run
29
- - example/Runfile
30
- - example/dancing/bouncing
31
- - example/salsa/cubana
32
- - example/school/fun
33
- - flash.gemspec
37
+ - exe/flash
34
38
  - lib/flash.rb
35
- - lib/flash/runfile.rb
36
- - lib/flash/runner.rb
39
+ - lib/flash/cli.rb
40
+ - lib/flash/command.rb
41
+ - lib/flash/command/base.rb
42
+ - lib/flash/command/clone.rb
43
+ - lib/flash/command/info.rb
44
+ - lib/flash/command/run.rb
45
+ - lib/flash/config.rb
37
46
  - lib/flash/version.rb
47
+ - spec/flash/cli_spec.rb
48
+ - spec/flash/command/base_spec.rb
49
+ - spec/flash/command/clone_spec.rb
50
+ - spec/flash/command/info_spec.rb
51
+ - spec/flash/command/run_spec.rb
52
+ - spec/flash/config_spec.rb
53
+ - spec/flash_spec.rb
38
54
  - spec/spec_helper.rb
39
55
  homepage: http://github.com/colmarius/flash
40
56
  licenses:
41
- - MIT
57
+ - Apache-2.0
58
+ metadata: {}
42
59
  post_install_message:
43
60
  rdoc_options: []
44
61
  require_paths:
45
62
  - lib
46
63
  required_ruby_version: !ruby/object:Gem::Requirement
47
- none: false
48
64
  requirements:
49
65
  - - ! '>='
50
66
  - !ruby/object:Gem::Version
51
67
  version: '0'
52
- segments:
53
- - 0
54
- hash: -4469809819880840159
55
68
  required_rubygems_version: !ruby/object:Gem::Requirement
56
- none: false
57
69
  requirements:
58
70
  - - ! '>='
59
71
  - !ruby/object:Gem::Version
60
72
  version: '0'
61
- segments:
62
- - 0
63
- hash: -4469809819880840159
64
73
  requirements: []
65
- rubyforge_project: flash
66
- rubygems_version: 1.8.25
74
+ rubyforge_project:
75
+ rubygems_version: 2.3.0
67
76
  signing_key:
68
- specification_version: 3
69
- summary: Flash helps you run commands on multiple projects all defined in the Runfile
77
+ specification_version: 4
78
+ summary: Flash helps you run same commands on multiple projects all defined in the
79
+ `.flash.yml` config.
70
80
  test_files: []
data/.gitignore DELETED
@@ -1 +0,0 @@
1
- *.gem
data/Gemfile DELETED
@@ -1,8 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
4
-
5
- group :development do
6
- gem 'rake', '~> 0.9'
7
- gem 'rspec', '~> 2.0'
8
- end
@@ -1,26 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- flash (0.0.3)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- diff-lcs (1.2.5)
10
- rake (0.9.6)
11
- rspec (2.14.1)
12
- rspec-core (~> 2.14.0)
13
- rspec-expectations (~> 2.14.0)
14
- rspec-mocks (~> 2.14.0)
15
- rspec-core (2.14.7)
16
- rspec-expectations (2.14.4)
17
- diff-lcs (>= 1.1.3, < 2.0)
18
- rspec-mocks (2.14.4)
19
-
20
- PLATFORMS
21
- ruby
22
-
23
- DEPENDENCIES
24
- flash!
25
- rake (~> 0.9)
26
- rspec (~> 2.0)
data/Rakefile DELETED
@@ -1,16 +0,0 @@
1
- require "rspec/core/rake_task"
2
-
3
- RSpec::Core::RakeTask.new do |task|
4
- task.name = 'spec'
5
- task.rspec_opts = ['-c',' -f', 'd']
6
- end
7
-
8
- task :build do
9
- system "gem build flash.gemspec"
10
- end
11
-
12
- task :release => :build do
13
- system "gem push flash-#{Flash::VERSION}.gem"
14
- end
15
-
16
- task :default => :spec
data/bin/run DELETED
@@ -1,44 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'optparse'
4
- require 'pathname'
5
- require 'flash'
6
- require 'flash/runner'
7
-
8
- options = {}
9
- optparse = OptionParser.new do |opts|
10
- opts.banner = "Usage: run [options] group"
11
-
12
- opts.on("-c", "--command command", String, "Commands to run (semicolon separated)") do |command|
13
- options[:commands] = command.split(';').map(&:strip)
14
- end
15
-
16
- opts.on("-d", "--debug", "Debug: print each command result") do |d|
17
- options[:debug] = d
18
- end
19
-
20
- opts.on("-r", "--recipe recipe", "Run registered recipe if present") do |recipe|
21
- options[:recipe] = recipe
22
- end
23
-
24
- opts.on("-l", "--list-recipes", "List registered recipes") do |l|
25
- options[:list_recipes] = l
26
- end
27
-
28
- opts.on("-h", "--help", "Help documentation") do
29
- puts opts ; exit
30
- end
31
-
32
- opts
33
- end
34
-
35
- optparse.parse!
36
-
37
- if ARGV.empty?
38
- puts "Group name is missing."
39
- puts optparse ; exit
40
- end
41
-
42
- group = ARGV[0]
43
-
44
- Flash::Runner.new(options, group).start
@@ -1,8 +0,0 @@
1
- projects:
2
- - salsa
3
- - dancing
4
- - school
5
-
6
- some:
7
- - salsa
8
- - school
@@ -1 +0,0 @@
1
- test
@@ -1 +0,0 @@
1
- test
@@ -1 +0,0 @@
1
- test
@@ -1,23 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
-
4
- require "flash/version"
5
-
6
- Gem::Specification.new do |gem|
7
- gem.name = "flash"
8
- gem.license = "MIT"
9
- gem.version = Flash::VERSION
10
-
11
- gem.author = ["Marius Colacioiu"]
12
- gem.email = ["marius.colacioiu@gmail.com"]
13
- gem.homepage = "http://github.com/colmarius/flash"
14
- gem.summary = %q{ Flash helps you run commands on multiple projects all defined in the Runfile }
15
-
16
- gem.description = gem.summary
17
-
18
- gem.rubyforge_project = "flash"
19
-
20
- gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
- gem.files = `git ls-files`.split("\n")
22
- gem.test_files = `git ls-files -- {spec}`.split("\n")
23
- end
@@ -1,19 +0,0 @@
1
- require 'flash'
2
- require 'yaml'
3
-
4
- class Flash::Runfile
5
-
6
- attr_reader :groups
7
-
8
- def initialize(filename=nil)
9
- load(filename) if filename
10
- end
11
-
12
- def [](name=nil)
13
- @groups[name] if name
14
- end
15
-
16
- def load(filename)
17
- @groups = YAML.load_file(filename) if File.exists?(filename)
18
- end
19
- end
@@ -1,80 +0,0 @@
1
- require 'flash'
2
- require 'flash/runfile'
3
-
4
- class Flash::Runner
5
- attr_reader :options
6
- attr_accessor :debug, :color, :dir_name, :runfile, :group
7
-
8
- def initialize(options = {}, group)
9
- raise "Missing required group parameter." unless group
10
-
11
- @options = options
12
- @runfile = Flash::Runfile.new('Runfile')
13
- @group = group
14
- end
15
-
16
- def pwd
17
- Dir.pwd
18
- end
19
-
20
- def run(command, verbose=true)
21
- say "#{ prompt }#{ command }" if verbose
22
- system "cd #{ app_dir } && #{ command }"
23
- say "[Debug] Result: #{ $?.inspect }" if verbose && debug
24
- end
25
-
26
- def recipes
27
- @recipes ||= {
28
- 'update-master' => 'git stash ; git checkout master ; git pull ; git stash pop',
29
- 'status' => 'git status -s',
30
- 'branch' => 'git branch'
31
- }
32
- end
33
-
34
- def list_recipes
35
- recipes.each_pair { |recipe, commands| puts %Q(#{ recipe }:\n\t"#{ commands }"\n\n) }
36
- end
37
-
38
- def commands(recipe)
39
- commands = recipes[recipe] ? recipes[recipe] : 'echo "Unknown recipe!"'
40
- commands.split(';').map(&:strip)
41
- end
42
-
43
- def say(stuff)
44
- prefix = "\e[38;5;#{ color }m"
45
- suffix = "\e[0m"
46
- system "echo '#{ prefix }#{ stuff }#{ suffix }'"
47
- end
48
-
49
- def change_color!
50
- self.color = rand((1..22)) * 10 + 2
51
- end
52
-
53
- def app_dir
54
- "#{ pwd }/#{ dir_name }"
55
- end
56
-
57
- def prompt
58
- "#{ dir_name }> "
59
- end
60
-
61
- def group_dirs
62
- runfile[group]
63
- end
64
-
65
- def start
66
- list_recipes and exit if options[:list_recipes]
67
-
68
- self.debug = options[:debug]
69
- group_dirs.each do |dir_name|
70
- change_color!
71
- self.dir_name = dir_name
72
- run "cd #{ pwd }/#{ dir_name }", false
73
-
74
- commands = options[:recipe] ? commands(options[:recipe]) : options[:commands]
75
- commands.each { |command| run(command) }\
76
-
77
- say ""
78
- end
79
- end
80
- end