rails-dev-tools 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +109 -0
- data/Rakefile +29 -0
- data/app/assets/config/dev_manifest.js +0 -0
- data/bin/dev +6 -0
- data/config/routes.rb +2 -0
- data/lib/dev.rb +12 -0
- data/lib/dev/engine.rb +4 -0
- data/lib/dev/executable.rb +205 -0
- data/lib/dev/executables/commands/feature.rb +111 -0
- data/lib/dev/executables/commands/hotfix.rb +121 -0
- data/lib/dev/executables/commands/pull.rb +51 -0
- data/lib/dev/executables/commands/push.rb +59 -0
- data/lib/dev/executables/commands/release.rb +133 -0
- data/lib/dev/executables/commands/status.rb +39 -0
- data/lib/dev/executables/commands/test.rb +49 -0
- data/lib/dev/executables/commands/version.rb +21 -0
- data/lib/dev/project.rb +131 -0
- data/lib/dev/rainbow.rb +29 -0
- data/lib/dev/version.rb +3 -0
- data/lib/generators/dev/config_generator.rb +18 -0
- data/lib/generators/templates/dev.yml.erb +44 -0
- data/lib/tasks/dev_tasks.rake +4 -0
- metadata +140 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8521d4f1cf1ae2731589db49050da30beb1b71b857cb47ae132f7c62be024af5
|
4
|
+
data.tar.gz: e6f4994b5adcd9ab50e043b2c348b58af9ae5ba837e78bff2503454d7fe40a0f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: aae21b0b0c2df5aa30e51e3beadeb801a233d3311ea36806b4dedc8680131f28a19872a01d2fe1b976b32242564ee9a52d4bccad059983cd08642861cdda8a16
|
7
|
+
data.tar.gz: 550f75d96be2edb8003d97ad4fec13a392e09e32e6ca1e5caccb377e393f78480fc09ca7704cda0b0e014ad3eba917a04e23847c439926fdecd3c1995245a8d8
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2018 Francesco Ballardin
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# Dev
|
2
|
+
This gem installs an executable command named `dev` which aims to help you develop and maintain Ruby or Ruby on Rails projects.
|
3
|
+
|
4
|
+
This gem takes inspiration from the Git Workflow published on [this page](https://nvie.com/posts/a-successful-git-branching-model/).
|
5
|
+
|
6
|
+
This gem can be used with mini Ruby projects composed of just one directory and a few files and at the same time with big Rails projects with many main apps and engines.
|
7
|
+
|
8
|
+
To work with big project, it is assumed that you organized your folders as follows:
|
9
|
+
|
10
|
+
```bash
|
11
|
+
/path/to/project/ # Main project directory
|
12
|
+
/path/to/project/main_apps # Main apps directory
|
13
|
+
/path/to/project/main_apps/app1 # Main app 1
|
14
|
+
/path/to/project/main_apps/app2 # Main app 2
|
15
|
+
...
|
16
|
+
/path/to/project/engines # Engines directory
|
17
|
+
/path/to/project/engines/engine1 # Engine 1
|
18
|
+
/path/to/project/engines/engine2 # Engine 2
|
19
|
+
...
|
20
|
+
```
|
21
|
+
|
22
|
+
## Installation
|
23
|
+
Install with:
|
24
|
+
```bash
|
25
|
+
$ gem install rails-dev-tools
|
26
|
+
```
|
27
|
+
|
28
|
+
This will install an executable command named `dev`.
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
From the shell run:
|
32
|
+
```
|
33
|
+
$ dev help
|
34
|
+
```
|
35
|
+
|
36
|
+
To list all the available commands.
|
37
|
+
|
38
|
+
## Commands
|
39
|
+
|
40
|
+
Usual git commands are `pull` and `push`. If you have a big project, this helps you pulling and pushing without moving from the current directory.
|
41
|
+
|
42
|
+
### Pull
|
43
|
+
|
44
|
+
To pull data for a specific main app or engine:
|
45
|
+
|
46
|
+
```bash
|
47
|
+
dev pull app1
|
48
|
+
dev pull engine2
|
49
|
+
```
|
50
|
+
|
51
|
+
To pull data for all main apps and engines:
|
52
|
+
```
|
53
|
+
dev pull
|
54
|
+
```
|
55
|
+
|
56
|
+
### Push
|
57
|
+
|
58
|
+
To push data for a specific main app or engine:
|
59
|
+
|
60
|
+
```bash
|
61
|
+
dev push app1 "commit message"
|
62
|
+
dev push engine2 "commit message"
|
63
|
+
```
|
64
|
+
|
65
|
+
### Feature
|
66
|
+
|
67
|
+
If you want to start developing a new feature:
|
68
|
+
```bash
|
69
|
+
dev feature open my-new-feat
|
70
|
+
```
|
71
|
+
|
72
|
+
You will be placed on a new branch called `feature/my-new-feat`. Do all your work and then push it. After that, you can close your feature with:
|
73
|
+
```bash
|
74
|
+
dev feature close my-new-feat
|
75
|
+
```
|
76
|
+
|
77
|
+
This will merge the feature branch on the `develop` branch.
|
78
|
+
|
79
|
+
### Release
|
80
|
+
|
81
|
+
When all your work into the develop branch is ready to become a new release, run:
|
82
|
+
|
83
|
+
```bash
|
84
|
+
dev release open 0.2.0
|
85
|
+
```
|
86
|
+
|
87
|
+
You will be placed on a new branch called `release/0.2.0`. You can work on this branch until it becomes stable and passes all tests. At this point commit and push your work and then run:
|
88
|
+
```
|
89
|
+
dev release close 0.2.0
|
90
|
+
```
|
91
|
+
|
92
|
+
This will merge the release branch on the `master` branch.
|
93
|
+
|
94
|
+
### Hotfix
|
95
|
+
|
96
|
+
If you need to quickly fix a bug that accidentally made it to production, run:
|
97
|
+
```bash
|
98
|
+
dev hotfix open 0.2.1
|
99
|
+
```
|
100
|
+
|
101
|
+
You will be placed on a new branch called `hotfix/0.2.1`. While on this branch, write only code that fixes the bug(s) found. Do not start new features or continue developing existing ones. When you have fixed the bug run:
|
102
|
+
```bash
|
103
|
+
dev hotfix close 0.2.1
|
104
|
+
```
|
105
|
+
|
106
|
+
This will merge the hotfix branch on the `master` branch and on the `develop` branch.
|
107
|
+
|
108
|
+
## License
|
109
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Dev'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
load 'rails/tasks/statistics.rake'
|
18
|
+
|
19
|
+
require 'bundler/gem_tasks'
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
|
23
|
+
Rake::TestTask.new(:test) do |t|
|
24
|
+
t.libs << 'test'
|
25
|
+
t.pattern = 'test/**/*_test.rb'
|
26
|
+
t.verbose = false
|
27
|
+
end
|
28
|
+
|
29
|
+
task default: :test
|
File without changes
|
data/bin/dev
ADDED
data/config/routes.rb
ADDED
data/lib/dev.rb
ADDED
data/lib/dev/engine.rb
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'dev/project'
|
3
|
+
require 'dev/executables/commands/version'
|
4
|
+
require 'dev/executables/commands/status'
|
5
|
+
require 'dev/executables/commands/feature'
|
6
|
+
require 'dev/executables/commands/hotfix'
|
7
|
+
require 'dev/executables/commands/release'
|
8
|
+
require 'dev/executables/commands/pull'
|
9
|
+
require 'dev/executables/commands/push'
|
10
|
+
require 'dev/executables/commands/test'
|
11
|
+
|
12
|
+
module Dev
|
13
|
+
|
14
|
+
##
|
15
|
+
# Classe per gestire l'esecuzione del comando +dev+.
|
16
|
+
class Executable
|
17
|
+
|
18
|
+
##
|
19
|
+
# Definisce la classe per tutti gli errori interni
|
20
|
+
# all'esecuzione.
|
21
|
+
class ExecutionError < StandardError; end
|
22
|
+
|
23
|
+
include Dev::Executables::Commands::Version
|
24
|
+
include Dev::Executables::Commands::Status
|
25
|
+
include Dev::Executables::Commands::Feature
|
26
|
+
include Dev::Executables::Commands::Hotfix
|
27
|
+
include Dev::Executables::Commands::Release
|
28
|
+
include Dev::Executables::Commands::Pull
|
29
|
+
include Dev::Executables::Commands::Push
|
30
|
+
include Dev::Executables::Commands::Test
|
31
|
+
|
32
|
+
# @return [Dev::Executables::Project] il progetto di riferimento.
|
33
|
+
attr_accessor :project
|
34
|
+
# @return [StandardError] l'errore riscontrato, se presente.
|
35
|
+
attr_accessor :error
|
36
|
+
# @return [String] il backtrace dell'errore, se presente.
|
37
|
+
attr_accessor :backtrace
|
38
|
+
|
39
|
+
##
|
40
|
+
# Inizializza l'eseguibile, in base al comando passato.
|
41
|
+
#
|
42
|
+
# @param [Array] argv gli argomenti del comando.
|
43
|
+
def initialize(*argv)
|
44
|
+
begin
|
45
|
+
if argv[0].present?
|
46
|
+
if self.respond_to?(argv[0])
|
47
|
+
# Carica i dati del progetto
|
48
|
+
load_project
|
49
|
+
# Lancia il comando passato
|
50
|
+
if self.method(argv[0]).arity.abs > 0
|
51
|
+
self.send(argv[0], *argv[1..-1])
|
52
|
+
else
|
53
|
+
self.send(argv[0])
|
54
|
+
end
|
55
|
+
else
|
56
|
+
raise ExecutionError.new "Command '#{argv[0]}' is not supported. Run "\
|
57
|
+
"'dev help' for a list of available commands."
|
58
|
+
end
|
59
|
+
else
|
60
|
+
raise ExecutionError.new "Missing required parameters. Run 'dev help' "\
|
61
|
+
"for a list of available commands."
|
62
|
+
end
|
63
|
+
rescue Dev::Executable::ExecutionError => e
|
64
|
+
@error = e.message
|
65
|
+
puts @error.red
|
66
|
+
rescue StandardError => e
|
67
|
+
@error = "#{e.class}: #{e.message}"
|
68
|
+
@backtrace = e.backtrace.join("\n")
|
69
|
+
puts @error.red
|
70
|
+
puts @backtrace.red
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Carica i dati del progetto prendendoli dal file
|
76
|
+
# di configurazione del file 'dev.yml'.
|
77
|
+
#
|
78
|
+
# @return [nil]
|
79
|
+
def load_project
|
80
|
+
config_file = Dir.glob("#{Dir.pwd}/**/dev.yml").first
|
81
|
+
raise ExecutionError.new "No valid configuration files found. Searched for a file named 'dev.yml' "\
|
82
|
+
"in folder #{Dir.pwd} and all its subdirectories." if config_file.nil?
|
83
|
+
@project = Dev::Project.new(config_file)
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# Determina de l'env è valido.
|
88
|
+
#
|
89
|
+
# @return [Boolean] se l'env è fra quelli validi.
|
90
|
+
def valid_env?
|
91
|
+
unless @env.in? [ :production, :staging ]
|
92
|
+
raise ExecutionError.new "The environment '#{@env}' is not valid. "\
|
93
|
+
"Valid environments are 'production' or 'staging'."
|
94
|
+
else
|
95
|
+
true
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
##
|
100
|
+
# Esegue un comando e cattura l'output ritornandolo come
|
101
|
+
# risultato di questo metodo. Si può passare l'opzione
|
102
|
+
# +flush+ per stampare subito l'output come se non fosse stato
|
103
|
+
# catturato.
|
104
|
+
#
|
105
|
+
# @param [String] command il comando da eseguire.
|
106
|
+
# @param [Hash] options le opzioni.
|
107
|
+
#
|
108
|
+
# @return [nil]
|
109
|
+
def exec(command, options = {})
|
110
|
+
out, err, status = Open3.capture3(command)
|
111
|
+
command_output = [ out.presence, err.presence ].compact.join("\n")
|
112
|
+
if options[:flush] == true
|
113
|
+
puts command_output
|
114
|
+
else
|
115
|
+
command_output
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
##
|
120
|
+
# Stampa i comandi possibili.
|
121
|
+
#
|
122
|
+
# @return [nil]
|
123
|
+
def help
|
124
|
+
puts
|
125
|
+
print "Dev".green
|
126
|
+
print " - available commands:\n"
|
127
|
+
puts
|
128
|
+
|
129
|
+
print "\tversion\t\t".limegreen
|
130
|
+
print "Prints current version.\n"
|
131
|
+
puts
|
132
|
+
|
133
|
+
print "\tfeature\t\t".limegreen
|
134
|
+
print "Opens or closes a feature for the current app.\n"
|
135
|
+
print "\t\t\tWarning: the app is determined from the current working directory!\n"
|
136
|
+
print "\t\t\tExample: "
|
137
|
+
print "dev feature open my-new-feature".springgreen
|
138
|
+
print " (opens a new feature for the current app)"
|
139
|
+
print ".\n"
|
140
|
+
print "\t\t\tExample: "
|
141
|
+
print "dev feature close my-new-feature".springgreen
|
142
|
+
print " (closes a developed new feature for the current app)"
|
143
|
+
print ".\n"
|
144
|
+
puts
|
145
|
+
|
146
|
+
print "\thotfix\t\t".limegreen
|
147
|
+
print "Opens or closes a hotfix for the current app.\n"
|
148
|
+
print "\t\t\tWarning: the app is determined from the current working directory!\n"
|
149
|
+
print "\t\t\tExample: "
|
150
|
+
print "dev hotfix open 0.2.1".springgreen
|
151
|
+
print " (opens a new hotfix for the current app)"
|
152
|
+
print ".\n"
|
153
|
+
print "\t\t\tExample: "
|
154
|
+
print "dev hotfix close 0.2.1".springgreen
|
155
|
+
print " (closes a developed new hotfix for the current app)"
|
156
|
+
print ".\n"
|
157
|
+
puts
|
158
|
+
|
159
|
+
print "\trelease\t\t".limegreen
|
160
|
+
print "Opens or closes a release for the current app.\n"
|
161
|
+
print "\t\t\tWarning: the app is determined from the current working directory!\n"
|
162
|
+
print "\t\t\tExample: "
|
163
|
+
print "dev release open 0.2.0".springgreen
|
164
|
+
print " (opens a new release for the current app)"
|
165
|
+
print ".\n"
|
166
|
+
print "\t\t\tExample: "
|
167
|
+
print "dev release close 0.2.0".springgreen
|
168
|
+
print " (closes a developed new release for the current app)"
|
169
|
+
print ".\n"
|
170
|
+
puts
|
171
|
+
|
172
|
+
print "\tpull\t\t".limegreen
|
173
|
+
print "Pulls specified app's git repository, or pulls all apps if none are specified.\n"
|
174
|
+
print "\t\t\tWarning: the pulled branch is the one the app is currently on!\n"
|
175
|
+
print "\t\t\tExample: "
|
176
|
+
print "dev pull [myapp]".springgreen
|
177
|
+
print ".\n"
|
178
|
+
puts
|
179
|
+
|
180
|
+
print "\tpush\t\t".limegreen
|
181
|
+
print "Commits and pushes the specified app.\n"
|
182
|
+
print "\t\t\tWarning: the pushed branch is the one the app is currently on!\n"
|
183
|
+
print "\t\t\tExample: "
|
184
|
+
print "dev push myapp \"commit message\"".springgreen
|
185
|
+
print ".\n"
|
186
|
+
puts
|
187
|
+
|
188
|
+
print "\ttest\t\t".limegreen
|
189
|
+
print "Runs the app's test suite. Tests must be written with rspec.\n"
|
190
|
+
print "\t\t\tIt is possibile to specify which app's test suite to run.\n"
|
191
|
+
print "\t\t\tIf nothing is specified, all main app's test suites are run.\n"
|
192
|
+
print "\t\t\tExample: "
|
193
|
+
print "dev test mymainapp myengine".springgreen
|
194
|
+
print " (runs tests for 'mymainapp' and 'myengine')"
|
195
|
+
print ".\n"
|
196
|
+
print "\t\t\tExample: "
|
197
|
+
print "dev test".springgreen
|
198
|
+
print " (runs tests for all main apps and engines within this project)"
|
199
|
+
print ".\n"
|
200
|
+
puts
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Dev
|
2
|
+
module Executables
|
3
|
+
module Commands
|
4
|
+
module Feature
|
5
|
+
|
6
|
+
##
|
7
|
+
# Comandi per gestire l'apertura e la chiusura di una nuova feature.
|
8
|
+
#
|
9
|
+
# @param [String] command il comando da eseguire.
|
10
|
+
# @param [String] name il nome della feature.
|
11
|
+
#
|
12
|
+
# @return [nil]
|
13
|
+
def feature(command = nil, name = nil)
|
14
|
+
raise Dev::Executable::ExecutionError.new "Wrong command syntax: "\
|
15
|
+
"specify whether to open or close a feature. "\
|
16
|
+
"Example: dev feature open my-new-feature" unless command.in? [ 'open', 'close' ]
|
17
|
+
name = name.to_s.squish
|
18
|
+
|
19
|
+
if @project.valid_app?
|
20
|
+
case command
|
21
|
+
when 'open' then feature_open(name)
|
22
|
+
when 'close' then feature_close(name)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Apre una nuova feature.
|
29
|
+
#
|
30
|
+
# @param [String] name il nome della feature.
|
31
|
+
#
|
32
|
+
# @return [nil]
|
33
|
+
def feature_open(name)
|
34
|
+
print "Preparing to open a new feature for app "
|
35
|
+
print @project.current_app.teal
|
36
|
+
print " named "
|
37
|
+
puts name.teal
|
38
|
+
puts
|
39
|
+
|
40
|
+
branches = `git branch -a`
|
41
|
+
unless branches.include? ("develop\n")
|
42
|
+
print "\tCreating develop branch.."
|
43
|
+
exec "git checkout -b develop"
|
44
|
+
exec "git add ."
|
45
|
+
exec "git commit -m \"Dev: automatically created 'develop' branch\""
|
46
|
+
exec "git push -u origin develop"
|
47
|
+
print "√\n".green
|
48
|
+
puts
|
49
|
+
end
|
50
|
+
|
51
|
+
print "\tOpening.. "
|
52
|
+
git_output = exec "git checkout -b feature/#{name} develop"
|
53
|
+
if git_output.include?('fatal') or git_output.include?('rejected') or git_output.include?('error')
|
54
|
+
print "X\n".red
|
55
|
+
puts "\t\tSomething went wrong, take a look at the output from git:".indianred
|
56
|
+
puts "\t\t#{git_output.split("\n").map(&:squish).join("\n\t\t")}".indianred
|
57
|
+
puts
|
58
|
+
else
|
59
|
+
print "√\n".green
|
60
|
+
puts "\t\tDone. Output from git:".cadetblue
|
61
|
+
puts "\t\t#{git_output.split("\n").map(&:squish).join("\n\t\t")}".cadetblue
|
62
|
+
puts
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Chiude una feature esistente.
|
68
|
+
#
|
69
|
+
# @param [String] name il nome della feature.
|
70
|
+
#
|
71
|
+
# @return [nil]
|
72
|
+
def feature_close(name)
|
73
|
+
print "Preparing to close the feature for app "
|
74
|
+
print @project.current_app.teal
|
75
|
+
print " named "
|
76
|
+
puts name.teal
|
77
|
+
puts
|
78
|
+
|
79
|
+
status = `git status`
|
80
|
+
if status.include? "Changes not staged for commit:"
|
81
|
+
raise Dev::Executable::ExecutionError.new "Your current branch has unstaged changes. Please "\
|
82
|
+
"commit or stash them before closing the feature."
|
83
|
+
end
|
84
|
+
|
85
|
+
branches = `git branch -a`
|
86
|
+
unless branches.include? ("feature/#{name}\n")
|
87
|
+
raise Dev::Executable::ExecutionError.new "No feature named '#{name}' could be found "\
|
88
|
+
"for this app's repository."
|
89
|
+
end
|
90
|
+
|
91
|
+
print "\tClosing.. "
|
92
|
+
exec "git checkout develop"
|
93
|
+
exec "git merge --no-ff feature/#{name}"
|
94
|
+
git_output = exec "git push origin develop"
|
95
|
+
if git_output.include?('fatal') or git_output.include?('rejected') or git_output.include?('error')
|
96
|
+
print "X\n".red
|
97
|
+
puts "\t\tSomething went wrong, take a look at the output from git:".indianred
|
98
|
+
puts "\t\t#{git_output.split("\n").map(&:squish).join("\n\t\t")}".indianred
|
99
|
+
puts
|
100
|
+
else
|
101
|
+
print "√\n".green
|
102
|
+
puts "\t\tDone. Output from git:".cadetblue
|
103
|
+
puts "\t\t#{git_output.split("\n").map(&:squish).join("\n\t\t")}".cadetblue
|
104
|
+
puts
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|