git_commands 3.4.0 → 3.5.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c4e5ee0c7fb792943323a8df9f026e46ed043c2e
4
- data.tar.gz: a1d6e9c1709de3a742c9c20aa22cfbd6bdc86290
3
+ metadata.gz: 172e8dcb4ab65fc7f43efc68e42709b8730fb54b
4
+ data.tar.gz: 8a9fa030b351e83b13e3dd4ea7a5c0684670a05d
5
5
  SHA512:
6
- metadata.gz: 725df66a77dd900e4f2c2aa5543c1e25ffc24d62cc332bc9e8fb7d7d29123f0eac821a57b8912d56c039eebcc1135f3ae1187531cddcfeb10c8f204e87854d53
7
- data.tar.gz: 2b3162474ae63758828d6c1e9dc071c813a92565200e7a69d91c4808507718f11b62a05ab6598da26035e7c4fc95c3c6db38e6724f2d2c5ffda8b9a899836042
6
+ metadata.gz: 0adf55993c9add401986a9d019e712998813b087bcbbb27bcb339daaddab77a9c2ba3ddb8af7191c884462b6f7c05e55591323b7cd30dd96c5f4679cf1d7d070
7
+ data.tar.gz: 5222cf662d765a7fd08cbd31bb357abe849f2b5c42974c599a1b5e1462b4cb065720c58b5f6eb0a4d74298af3e770bf87efd97a7a7f35092be5b59084906fa3e
data/README.md CHANGED
@@ -16,9 +16,8 @@
16
16
  ## Workflow
17
17
  This script facilitates adopting a subset of the branch-featuring workflow characterised by:
18
18
  * each feature will have its own branch
19
- * feature branches derive directly form master
20
- * integration of master to feature branch happens via rebasing to maintain a straight commits line
21
- * force pushing of feature branches to origin is not an issue
19
+ * integration of feature branch with defaukt one happens via rebasing to maintain a straight commits line
20
+ * is not an issue to `force-with-lease` push feature pranch to origin
22
21
  * release branches are created aggregating multiple branches
23
22
 
24
23
  ## Scope
@@ -48,10 +47,11 @@ Display the help of a specific command by:
48
47
 
49
48
  ```
50
49
  rebase --help
51
- Usage: rebase --repo=/Users/Elvis/greatest_hits --branches=feature/love_me_tender,fetaure/teddybear
50
+ Usage: rebase --repo=/Users/Elvis/greatest_hits --origin=upstream --default=production --branches=feature/love_me_tender,fetaure/teddybear
52
51
  -r, --repo=REPO The path to the existing GIT repository
52
+ -o, --origin=ORIGIN Specify the remote alias (origin)
53
+ -d, --default=DEFAULT Specify the default branch (master)
53
54
  -b, --branches=BRANCHES Specify branches as: 1. a comma-separated list of names 2. the path to a file containing names on each line 3. via pattern matching
54
- -t, --target=TARGET Specify the target branch, default to master
55
55
  -h, --help Prints this help
56
56
  ```
57
57
 
@@ -133,8 +133,8 @@ rebase --repo=/Users/Elvis/greatest_hits --branches=noent1,noent2
133
133
  No branches loaded!
134
134
  ```
135
135
 
136
- ##### Master branch
137
- Master branch cannot be included into the branches list for obvious reasons:
136
+ ##### Default branch
137
+ Default branch cannot be included into the branches list for obvious reasons:
138
138
 
139
139
  ```
140
140
  rebase --repo=/Users/Elvis/greatest_hits --branches=master,feature/love_me_tender
@@ -148,7 +148,7 @@ Successfully loaded 1 branch:
148
148
  Here are the available GIT commands:
149
149
 
150
150
  #### Rebase
151
- This command is useful in case you have several branches to rebase with _origin/master_ (or another specified target) frequently.
151
+ This command is useful in case you have to rebase several branches with _origin/master_ (or another specified default) frequently.
152
152
  A confirmation is asked to before rebasing.
153
153
 
154
154
  ```
@@ -156,17 +156,17 @@ rebase --repo=/Users/Elvis/greatest_hits --branches=feature/love_me_tender,featu
156
156
  ...
157
157
  ```
158
158
 
159
- ##### Target branch
160
- The rebasing runs considering master branch as the target one.
161
- In case you need to rebase against a different target branch you can specify it:
159
+ ##### Changing origin
160
+ The rebasing runs considering `master` branch as the default one and `origin` as the remote alias.
161
+ In case you need to rebase against a different origin and default branch you can specify them by command line:
162
162
  ```
163
- rebase --repo=/Users/Elvis/greatest_hits --target=rc/release_to_graceland --branches=feature/love_me_tender
163
+ rebase --repo=/Users/Elvis/greatest_hits --origin=upstream --default=production --branches=feature/love_me_tender
164
164
 
165
165
  Loading branches file...
166
166
  Successfully loaded 1 branch:
167
167
  01. feature/love_me_tender
168
168
 
169
- Proceed rebasing these branches with rc/release_to_graceland (Y/N)?
169
+ Proceed rebasing these branches with upstream/production (Y/N)?
170
170
  ```
171
171
 
172
172
  #### Remove
@@ -180,10 +180,45 @@ remove --repo=/temp/top_20 --branches=*obsolete*
180
180
 
181
181
  #### Aggregate
182
182
  This command aggregates all of the specified branches into a single one in case you want to create a release branch.
183
- The created aggregate branch follows this naming convention: *aggregate/yyyy_mm_dd*
184
183
  A confirmation is asked before aggregating.
185
184
 
186
185
  ```
187
186
  aggregate --repo=/Users/Elvis/greatest_hits --branches=*ready*
188
187
  ...
189
188
  ```
189
+
190
+ ##### Aggregate naming
191
+ The created aggregate branch follows a default naming convention pattern:
192
+ `aggregate/<timestamp>`
193
+
194
+ Each of the term within the `<` and `>` chars are replaced by related (upcased) environment variables, but for the `timestamp`, that is computed at runtime in the `yyyymmdd` format.
195
+ Consider a valid pattern should at least contain one replaceable part within the `<` and `>` chars.
196
+
197
+ You can overwrite the naming pattern by specifying the following environment variables:
198
+ * `AGGREGATE_NAME` - the name to be used directly for the aggregator branch, without any pattern replacements
199
+ * `AGGREGATE_PATTERN` - change the default pattern by specifying the related environment variables for each parts within the `<` and `>` chars
200
+
201
+ ###### Examples
202
+ Passing directly the aggregate name:
203
+ ```shell
204
+ AGGREGATE_NAME=my_aggregate aggregate --repo=/Users/Elvis/greatest_hits --branches=*ready*
205
+ ...
206
+ Aggregate branches into my_aggregate (Y/N)?
207
+ ```
208
+
209
+ Using the default pattern:
210
+ ```shell
211
+ aggregate --repo=/Users/Elvis/greatest_hits --branches=*ready*
212
+ ...
213
+ Aggregate branches into release/20170307 (Y/N)?
214
+ ```
215
+
216
+ Using a custom pattern:
217
+ ```shell
218
+ RELEASE_TYPE=bugfix \
219
+ RISK=HIGH \
220
+ PROGRESSIVE=3 \
221
+ AGGREGATE_PATTERN="release/rc-<progressive>.<release_type>_<risk>_<timestamp>" aggregate --repo=/Users/Elvis/greatest_hits --branches=*ready*
222
+ ...
223
+ Aggregate branches into release/rc-3.bugfix_HIGH_20170307 (Y/N)?
224
+ ```
@@ -0,0 +1,43 @@
1
+ module GitCommands
2
+ class Aggregator
3
+ PATTERN = ENV.fetch("AGGREGATE_PATTERN") { "release/<timestamp>" }
4
+ NAME = ENV["AGGREGATE_NAME"]
5
+
6
+ class InvalidPatternError < ArgumentError; end
7
+
8
+ def initialize(name: NAME, pattern: PATTERN)
9
+ @name = name
10
+ @pattern = check_pattern(pattern)
11
+ define_methods
12
+ end
13
+
14
+ def timestamp
15
+ @timestamp ||= Time.new.strftime("%Y%m%d")
16
+ end
17
+
18
+ def call
19
+ return @name if @name
20
+ @pattern.gsub(/<[\w_]+>/) do |part|
21
+ msg = part.gsub(/<|>/, "")
22
+ send(msg)
23
+ end
24
+ end
25
+
26
+ private def check_pattern(pattern)
27
+ fail InvalidPatternError unless pattern.match(/<\w+>/)
28
+ pattern
29
+ end
30
+
31
+ private def pattern_methods
32
+ @methods ||= @pattern.scan(/<(\w+)>/).flatten - ["timestamp"]
33
+ end
34
+
35
+ def define_methods
36
+ pattern_methods.each do |name|
37
+ define_singleton_method(name) do
38
+ ENV.fetch(name.upcase) { "" }
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -3,11 +3,11 @@ require "pathname"
3
3
  module GitCommands
4
4
  using Colorize
5
5
  class Branch
6
- MASTER = "master"
7
- ORIGIN = "origin/"
6
+ DEFAULT = "master"
7
+ ORIGIN = "origin"
8
8
 
9
9
  def self.strip_origin(name)
10
- name.strip.split(ORIGIN).last
10
+ name.strip.split("#{ORIGIN}/").last
11
11
  end
12
12
 
13
13
  def self.by_file(path)
@@ -19,9 +19,9 @@ module GitCommands
19
19
 
20
20
  def self.by_pattern(pattern)
21
21
  return [] unless pattern.index("*")
22
- `git branch -r --list #{ORIGIN}#{pattern}`.split("\n").map do |name|
22
+ `git branch -r --list #{ORIGIN}/#{pattern}`.split("\n").map do |name|
23
23
  new(strip_origin(name))
24
- end.reject(&:master?)
24
+ end.reject(&:default?)
25
25
  end
26
26
 
27
27
  def self.by_names(names_list)
@@ -54,7 +54,7 @@ module GitCommands
54
54
  end
55
55
 
56
56
  def valid?
57
- return false if master?
57
+ return false if default?
58
58
  return false unless exists?
59
59
  true
60
60
  end
@@ -63,12 +63,12 @@ module GitCommands
63
63
  self.name == other.name
64
64
  end
65
65
 
66
- def master?
67
- @name == MASTER
66
+ def default?
67
+ @name == DEFAULT
68
68
  end
69
69
 
70
70
  def exists?(remote = true)
71
- origin = ORIGIN if remote
71
+ origin = "#{ORIGIN}/" if remote
72
72
  `git rev-parse --verify #{origin}#{@name} 2> /dev/null`.match(/^[0-9a-z]+/)
73
73
  end
74
74
  end
@@ -20,15 +20,15 @@ module GitCommands
20
20
 
21
21
  def call
22
22
  parser.parse!(@args)
23
- computer = @computer_klass.new(repo: @repo, branches: @branches, target: target)
23
+ computer = @computer_klass.new(repo: @repo, branches: @branches, origin: @origin, default: default)
24
24
  computer.send(@command_name)
25
25
  rescue Repository::PathError, Computer::GitError, AbortError, Repository::InvalidError => e
26
26
  error(e.message)
27
27
  exit
28
28
  end
29
29
 
30
- private def target
31
- @target || Branch::MASTER
30
+ private def default
31
+ @default || Branch::DEFAULT
32
32
  end
33
33
 
34
34
  private def check_command_name(name)
@@ -38,18 +38,22 @@ module GitCommands
38
38
 
39
39
  private def parser
40
40
  OptionParser.new do |opts|
41
- opts.banner = "Usage: #{@command_name} --repo=/Users/Elvis/greatest_hits --branches=feature/love_me_tender,fetaure/teddybear"
41
+ opts.banner = "Usage: #{@command_name} --repo=/Users/Elvis/greatest_hits --origin=upstream --default=production --branches=feature/love_me_tender,fetaure/teddybear"
42
42
 
43
43
  opts.on("-rREPO", "--repo=REPO", "The path to the existing GIT repository") do |repo|
44
44
  @repo = repo
45
45
  end
46
46
 
47
- opts.on("-bBRANCHES", "--branches=BRANCHES", "Specify branches as: 1. a comma-separated list of names 2. the path to a file containing names on each line 3. via pattern matching") do |branches|
48
- @branches = branches
47
+ opts.on("-oORIGIN", "--origin=ORIGIN", "Specify the remote alias (origin)") do |origin|
48
+ @origin = origin
49
+ end
50
+
51
+ opts.on("-dDEFAULT", "--default=DEFAULT", "Specify the default branch (master)") do |default|
52
+ @default = default
49
53
  end
50
54
 
51
- opts.on("-tTARGET", "--target=TARGET", "Specify the target branch, default to master") do |target|
52
- @target = target
55
+ opts.on("-bBRANCHES", "--branches=BRANCHES", "Specify branches as: 1. a comma-separated list of names 2. the path to a file containing names on each line 3. via pattern matching") do |branches|
56
+ @branches = branches
53
57
  end
54
58
 
55
59
  opts.on("-h", "--help", "Prints this help") do
@@ -1,6 +1,7 @@
1
1
  require "git_commands/prompt"
2
2
  require "git_commands/branch"
3
3
  require "git_commands/repository"
4
+ require "git_commands/aggregator"
4
5
 
5
6
  module GitCommands
6
7
  class Computer
@@ -9,15 +10,14 @@ module GitCommands
9
10
  class GitError < StandardError; end
10
11
 
11
12
  attr_reader :out
12
- attr_accessor :target
13
13
 
14
- def initialize(repo:, branches:, target: Branch::MASTER, repo_klass: Repository, branch_klass: Branch, out: STDOUT)
14
+ def initialize(repo:, branches:, origin: Branch::ORIGIN, default: Branch::DEFAULT, repo_klass: Repository, branch_klass: Branch, out: STDOUT)
15
15
  @out = out
16
16
  @repo = repo_klass.new(repo)
17
- @target = target
17
+ @origin = origin
18
+ @default = default
18
19
  Dir.chdir(@repo) do
19
20
  @branches = branch_klass.factory(branches)
20
- @timestamp = Time.new.strftime("%Y-%m-%d")
21
21
  print_branches
22
22
  end
23
23
  end
@@ -35,14 +35,14 @@ module GitCommands
35
35
  end
36
36
 
37
37
  def rebase
38
- confirm("Proceed rebasing these branches with #{@target}") do
38
+ confirm("Proceed rebasing these branches with: #{local_def}") do
39
39
  enter_repo do
40
40
  @branches.each do |branch|
41
41
  warning("Rebasing branch: #{branch}")
42
42
  `git checkout #{branch}`
43
- `git pull origin #{branch}`
43
+ `git pull -r origin #{branch}`
44
44
  next unless rebase_with
45
- `git push -f origin #{branch}`
45
+ `git push --force-with-lease origin #{branch}`
46
46
  success("Rebased successfully!")
47
47
  end
48
48
  remove_locals
@@ -50,23 +50,23 @@ module GitCommands
50
50
  end
51
51
  end
52
52
 
53
- def aggregate
54
- temp = "temp/#{@timestamp}"
55
- target = "aggregate/#{@timestamp}"
56
- confirm("Aggregate branches into #{target}") do
53
+ def aggregate(aggregator = Aggregator.new)
54
+ temp = "temp/#{aggregator.timestamp}"
55
+ aggregate_name = aggregator.call
56
+ confirm("Aggregate branches into #{aggregate_name}") do
57
57
  enter_repo do
58
- `git branch #{target}`
58
+ `git branch #{aggregate_name}`
59
59
  @branches.each do |branch|
60
60
  warning("Merging branch: #{branch}")
61
61
  `git checkout -b #{temp} origin/#{branch} --no-track`
62
- clean_and_exit([temp, target]) unless rebase_with
63
- clean_and_exit([temp]) unless rebase_with(target)
64
- `git checkout #{target}`
62
+ clean_and_exit([temp, aggregate_name]) unless rebase_with
63
+ clean_and_exit([temp]) unless rebase_with(aggregate_name)
64
+ `git checkout #{aggregate_name}`
65
65
  `git merge #{temp}`
66
66
  `git branch -D #{temp}`
67
67
  end
68
68
  end
69
- success("#{target} branch created")
69
+ success("#{aggregate_name} branch created")
70
70
  end
71
71
  end
72
72
 
@@ -79,11 +79,13 @@ module GitCommands
79
79
  end
80
80
 
81
81
  private def align
82
- `git checkout #{@target}`
83
- `git pull`
82
+ `git fetch #{@origin} #{@default}`
83
+ `git fetch origin`
84
+ `git checkout #{@default}`
85
+ `git pull -r`
84
86
  end
85
87
 
86
- private def rebase_with(branch = "#{Branch::ORIGIN}#{@target}")
88
+ private def rebase_with(branch = local_def)
87
89
  `git rebase #{branch}`
88
90
  return true unless @repo.locked?
89
91
  @repo.unlock
@@ -98,7 +100,7 @@ module GitCommands
98
100
  end
99
101
 
100
102
  private def remove_locals(branches = @branches)
101
- `git checkout #{@target}`
103
+ `git checkout #{@default}`
102
104
  branches.each do |branch|
103
105
  `git branch -D #{branch}`
104
106
  end
@@ -108,5 +110,9 @@ module GitCommands
108
110
  remove_locals(branches)
109
111
  exit
110
112
  end
113
+
114
+ private def local_def
115
+ "#{@origin}/#{@default}"
116
+ end
111
117
  end
112
118
  end
@@ -16,7 +16,7 @@ module GitCommands
16
16
  end
17
17
 
18
18
  def success(message)
19
- out.puts message.to_s.green
19
+ out.puts "\n#{message}".green
20
20
  true
21
21
  end
22
22
 
@@ -1,3 +1,3 @@
1
1
  module GitCommands
2
- VERSION = "3.4.0"
2
+ VERSION = "3.5.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git_commands
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.0
4
+ version: 3.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - costajob
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-27 00:00:00.000000000 Z
11
+ date: 2017-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -75,6 +75,7 @@ files:
75
75
  - bin/setup
76
76
  - git_commands.gemspec
77
77
  - lib/git_commands.rb
78
+ - lib/git_commands/aggregator.rb
78
79
  - lib/git_commands/branch.rb
79
80
  - lib/git_commands/cli.rb
80
81
  - lib/git_commands/colorize.rb