release-gem 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,224 @@
1
+
2
+ require 'gvcs'
3
+ require 'git_cli'
4
+
5
+ module Release
6
+ module Gem
7
+ module Action
8
+
9
+ class VcsActionError < StandardError; end
10
+
11
+ class VcsAction
12
+ include TR::CondUtils
13
+
14
+ attr_accessor :ui
15
+
16
+ def initialize(root, opts = { })
17
+ raise VcsActionError, "root cannot be null" if is_empty?(root)
18
+ @ws = Gvcs::Workspace.new(root)
19
+
20
+ oopts = opts || {}
21
+ @ui = oopts[:ui]
22
+ @engine = oopts[:engine]
23
+ st, path = @ws.workspace_root
24
+
25
+ #@gitDir = File.join(path.strip,".git")
26
+ #p @gitDir
27
+ #@gitBack = File.join(path.strip,".git_bak")
28
+ #p @gitBack
29
+ end
30
+
31
+ #def enable_dev_mode
32
+ # FileUtils.cp_r(@gitDir,@gitBack, remove_destination: true)
33
+ #end
34
+
35
+ #def dev_mode_end
36
+ # if File.exist?(@gitBack)
37
+ # FileUtils.mv(@gitBack, @gitDir)
38
+ # end
39
+ #end
40
+
41
+ def exec(&block)
42
+ instance_eval(&block) if block
43
+ end
44
+
45
+ def commit(msg = nil, &block)
46
+
47
+ res = :value
48
+ if block
49
+
50
+ counter = 0
51
+ loop do
52
+
53
+ stgDir, stgFiles = @ws.staged_files
54
+ modDir, modFiles = @ws.modified_files
55
+ newDir, newFiles = @ws.new_files
56
+ delDir, delFiles = @ws.deleted_files
57
+
58
+ modFiles.delete_if { |f| stgFiles.include?(f) }
59
+ modDir.delete_if { |f| stgDir.include?(f) }
60
+
61
+ # block should call vcs for add, remove, ignore and other operations
62
+ res = block.call(:select_files_to_commit, { modified: { files: modFiles, dirs: modDir }, new: { files: newFiles, dirs: newDir }, deleted: { files: delFiles, dirs: delDir }, staged: { files: stgFiles, dirs: stgDir }, vcs: self, counter: counter } )
63
+
64
+ break if res == :skip or res == :done
65
+
66
+ counter += 1
67
+
68
+ end
69
+
70
+ if res == :done
71
+
72
+ stgDir, stgFiles = @ws.staged_files
73
+ block.call(:staged_elements_of_commit, { files: stgFiles, dirs: stgDir })
74
+
75
+ msg = block.call(:commit_message) if is_empty?(msg)
76
+ raise VcsActionError, "Commit message is empty" if is_empty?(msg)
77
+
78
+ cp "Commit with user message : #{msg}"
79
+ st, res = @ws.commit(msg)
80
+ if st
81
+ block.call(:commit_successful, res) if block
82
+ else
83
+ block.call(:commit_failed, res) if block
84
+ end
85
+ [st, res]
86
+
87
+ end
88
+
89
+ else
90
+
91
+ msg = "Auto commit all ('-am' flag) by gem-release gem" if is_empty?(msg)
92
+ cp msg
93
+ # changed files only without new files
94
+ @ws.commit_all(msg)
95
+ end
96
+
97
+ res
98
+
99
+ end
100
+
101
+ def tag(*args, &block)
102
+
103
+ opts = args.first || { }
104
+ tag = opts[:tag]
105
+ msg = opts[:message]
106
+
107
+ if not @ws.tag_points_at?("HEAD")
108
+
109
+ if is_empty?(tag)
110
+ raise VcsActionError, "tag name cannot be empty" if not block
111
+ tag = block.call(:tag_name)
112
+ raise VcsActionError, "tag name cannot be empty" if is_empty?(tag)
113
+ end
114
+
115
+ if is_empty?(msg)
116
+ if block
117
+ msg = block.call(:tag_message)
118
+ end
119
+ end
120
+
121
+ cp "tagged with name : #{tag} and message : #{msg}"
122
+ st, res = @ws.create_tag(tag, msg)
123
+ if st
124
+ block.call(:tagging_success, res) if block
125
+ else
126
+ block.call(:tagging_failed, res) if block
127
+ end
128
+
129
+ [st, res]
130
+
131
+ else
132
+
133
+ block.call(:no_tagging_required) if block
134
+ [true, "No tagging required"]
135
+ end
136
+
137
+ end
138
+
139
+ def push(remote = nil, branch= nil, &block)
140
+
141
+ remoteConf = @ws.remote_config
142
+ if is_empty?(remoteConf)
143
+ if block
144
+ remote = block.call(:no_remote_repos_defined)
145
+ end
146
+ else
147
+ if is_empty?(remote)
148
+ if block
149
+ remote = block.call(:select_remote, remoteConf)
150
+ else
151
+ remote = remoteConf.keys.first
152
+ end
153
+ end
154
+ end
155
+
156
+ raise VcsActionError, "Push repository remote cannot be empty" if is_empty?(remote)
157
+
158
+ if remote != :skip
159
+
160
+ branch = @ws.current_branch if is_empty?(branch)
161
+
162
+
163
+ if is_local_ahead_of_remote?("#{remote}/#{branch}", branch)
164
+
165
+ cp "pushing to #{remote}/#{branch}"
166
+ st, res = @ws.push_changes_with_tags(remote, branch)
167
+
168
+ if st
169
+ block.call(:push_successful, res) if block
170
+ else
171
+ block.call(:push_failed, res) if block
172
+ end
173
+
174
+ [st, res]
175
+
176
+ else
177
+ block.call(:no_changes_to_push, { remote: remote, branch: branch }) if block
178
+ end
179
+ end
180
+
181
+ end
182
+
183
+ def add_to_staging(*files)
184
+ @ws.add_to_staging(*files)
185
+ end
186
+
187
+ def ignore(*files)
188
+ @ws.ignore(*files)
189
+ end
190
+
191
+ def remove_from_staging(*files)
192
+ @ws.remove_from_staging(*files)
193
+ end
194
+
195
+
196
+ private
197
+ def method_missing(mtd, *args, &block)
198
+ if @ws.respond_to?(mtd)
199
+ @ws.send(mtd, *args, &block)
200
+ else
201
+ if not @engine.nil? and @engine.respond_to?(mtd)
202
+ @engine.send(mtd, *args, &block)
203
+ else
204
+ super
205
+ end
206
+ end
207
+ end
208
+
209
+ def cp(msg)
210
+ Gem.cul(@ui, msg)
211
+ end
212
+ def ce(msg)
213
+ Gem.cue(@ui, msg)
214
+ end
215
+
216
+
217
+
218
+ end # class VcsAction
219
+
220
+ end # module Action
221
+
222
+ end # module Gem
223
+
224
+ end # module Release
@@ -0,0 +1,231 @@
1
+
2
+
3
+ require 'tty/prompt'
4
+ require_relative 'vcs_action'
5
+
6
+ module Release
7
+ module Gem
8
+ module Cli
9
+ class VcsAction
10
+ def initialize(root, opts = { })
11
+ opts = {} if opts.nil?
12
+ opts[:ui] = TTY::Prompt.new
13
+ @inst = Action::VcsAction.new(root,opts)
14
+ @prmt = TTY::Prompt.new
15
+ end
16
+
17
+ def exec(&block)
18
+ instance_eval(&block) if block
19
+ end
20
+
21
+ def commit(*args, &block)
22
+ res = @inst.commit do |ops, *args|
23
+
24
+ preset = false
25
+ if block
26
+ res = block.call(ops, *args)
27
+ if res.nil?
28
+ preset = true
29
+ else
30
+ res
31
+ end
32
+ else
33
+ preset = true
34
+ end
35
+
36
+ if preset
37
+
38
+ case ops
39
+ when :select_files_to_commit
40
+ mfiles = args.first
41
+ @prmt.puts "\n Files already added to staging : ".yellow
42
+ mfiles[:staged].each do |k,v|
43
+ v.each do |vv|
44
+ @prmt.puts " * #{vv}"
45
+ end
46
+ end
47
+
48
+ @prmt.puts ""
49
+
50
+ sel = @prmt.multi_select "\n Following are files that could be added to version control : ".yellow do |m|
51
+
52
+ [:modified, :new, :deleted].each do |cat|
53
+ mfiles[cat].each do |k,v|
54
+ v.each do |vv|
55
+ m.choice vv, vv.path
56
+ end
57
+ end
58
+
59
+ end
60
+
61
+ m.choice "Skip", :skip if mfiles[:counter] == 0
62
+ m.choice "Done", :done
63
+ m.choice "Abort", :abort
64
+ end
65
+
66
+ if sel.include?(:abort)
67
+ raise Release::Gem::Abort, "User aborted"
68
+ elsif sel.include?(:skip)
69
+ :skip
70
+ else
71
+ res = :done if sel.include?(:done)
72
+ s = sel.clone
73
+ s.delete_if { |e| e == :done }
74
+ if not_empty?(s)
75
+ st, cres = add_to_staging(*s) if not_empty?(s)
76
+ if st
77
+ @prmt.puts "\n Files added successfully".green
78
+ else
79
+ @prmt.puts "\n Files failed to be added. Message was : #{cres}".red
80
+ end
81
+ end
82
+
83
+ res
84
+
85
+ end
86
+
87
+ when :commit_message
88
+ msg = ""
89
+ loop do
90
+ msg = @prmt.ask("\n Commit message : ".yellow, required: true)
91
+ confirm = @prmt.yes?(" Commit message : #{msg}\n Proceed? No to provide a new commit message ".yellow)
92
+ if confirm
93
+ break
94
+ end
95
+ end
96
+
97
+ msg
98
+
99
+ when :staged_elements_of_commit
100
+
101
+ elements = args.first
102
+ @prmt.puts "\n Following files/directories shall be committed in this session : ".yellow
103
+ elements.each do |k,v|
104
+ v.each do |vv|
105
+ @prmt.puts " * #{vv}"
106
+ end
107
+ end
108
+
109
+ when :commit_successful
110
+ @prmt.puts "\n Changes committed".green
111
+ @prmt.puts args.first
112
+
113
+ when :commit_failed
114
+ @prmt.puts "\n Changes failed to be committed. Error was : #{args.first}"
115
+
116
+ end
117
+ end
118
+ end # commit
119
+
120
+ end # Commit
121
+
122
+ def tag(*args, &block)
123
+
124
+ @inst.tag(*args) do |ops, *args|
125
+
126
+ preset = false
127
+ if block
128
+ res = block.call(ops, *args)
129
+ if res.nil?
130
+ preset = true
131
+ else
132
+ res
133
+ end
134
+ else
135
+ preset = true
136
+ end
137
+
138
+ if preset
139
+
140
+ case ops
141
+ when :tag_message
142
+ @prmt.ask("\n Please provide message for the tag : ".yellow, value: "Auto tagging by gem-release gem during releasing version #{@selVer}", required: true)
143
+
144
+ when :tagging_success
145
+ @prmt.puts "\n Tagging of source code is successful.".green
146
+ @prmt.puts args.first
147
+
148
+ when :tagging_failed
149
+ @prmt.puts "\n Tagging of source code failed. Error was : #{args.first}".red
150
+
151
+ when :no_tagging_required
152
+ @prmt.puts "\n No tagging required. Source head is the tagged item ".green
153
+
154
+ end
155
+ end # preset ?
156
+
157
+ end
158
+
159
+ end # tag
160
+
161
+ def push(*args, &block)
162
+
163
+ @inst.push do |ops, *args|
164
+ preset = false
165
+ if block
166
+ res = block.call(ops, *args)
167
+ if res.nil?
168
+ preset = true
169
+ else
170
+ res
171
+ end
172
+ else
173
+ preset = true
174
+ end
175
+
176
+ if preset
177
+
178
+ case ops
179
+ when :select_remote
180
+ val = args.first
181
+ sel = @prmt.select("\n Please select one of the remote config below : ") do |m|
182
+ val.each do |k,v|
183
+ m.choice k, k
184
+ end
185
+ m.choice "Skip pushing source code", :skip
186
+ m.choice "Abort", :abort
187
+ end
188
+ raise Release::Gem::Abort, "User aborted" if sel == :abort
189
+
190
+ sel
191
+
192
+ when :no_remote_repos_defined
193
+ add = @prmt.yes?("\n No remote configuration defined. Add one now?")
194
+ if add
195
+ name = @prmt.ask("\n Name of the repository : ", value: "origin", required: true)
196
+ url = @prmt.ask("\n URL of the repository : ", required: true)
197
+
198
+ st, res = add_remote(name, url)
199
+ if st
200
+ @prmt.puts "\n Remote configuration added successfully".green
201
+ name
202
+ else
203
+ raise Release::Gem::Abort, "Failed to add remote configuration. Error was : #{res}"
204
+ end
205
+ end
206
+
207
+ when :push_successful
208
+ @prmt.puts "\n Push success!".green
209
+ @prmt.puts args.first
210
+
211
+ when :push_failed
212
+ @prmt.puts "\nPush failed. Error was : #{args.first}".red
213
+
214
+ when :no_changes_to_push
215
+ val = args.first
216
+ @prmt.puts "\n Local is in sync with remote (#{val[:remote]}/#{val[:branch]}). Push is not required. "
217
+ end
218
+ end
219
+
220
+ end
221
+
222
+ end # push
223
+
224
+ def method_missing(mtd, *args, &block)
225
+ @inst.send(mtd, *args, &block)
226
+ end
227
+
228
+ end
229
+ end
230
+ end
231
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Release
4
4
  module Gem
5
- VERSION = "0.1.0"
5
+ VERSION = "0.1.2"
6
6
  end
7
7
  end
@@ -0,0 +1,50 @@
1
+
2
+
3
+ require_relative '../lib/release/gem'
4
+ require 'tty/prompt'
5
+ require 'colorize'
6
+
7
+ namespace :gem do
8
+ desc "Release GEM standard workflow (gem-release gem)"
9
+ task :release do
10
+ # check for local flow
11
+ custom = Dir.glob(File.join(Dir.getwd, "*.relflow"))
12
+ if custom.length > 0
13
+
14
+ pmt = TTY::Prompt.new
15
+
16
+ begin
17
+ if custom.length > 1
18
+ sel = pmt.select("\n There are more than 1 release flow (*.relflow files) detected. Please select one for this session : ".yellow) do |m|
19
+ custom.each do |f|
20
+ m.choice f, f
21
+ end
22
+ end
23
+
24
+ require sel
25
+
26
+ else
27
+
28
+ #require custom.first
29
+ load custom.first
30
+
31
+ end
32
+ rescue TTY::Reader::InputInterrupt => ex
33
+ pmt.puts "\n Aborted"
34
+ end
35
+ else
36
+ stdFlow = File.join(File.dirname(__FILE__),"..","templates","standard_cli_flow")
37
+ require stdFlow
38
+ end
39
+ end
40
+
41
+ desc "Copy the standard flow to project local so modification of the flow is possible"
42
+ task :customize_flow do
43
+ stdFlow = File.join(File.dirname(__FILE__),"..","templates","standard_cli_flow.rb")
44
+ dest = File.join(Dir.getwd, "custom_flow.relflow")
45
+ FileUtils.cp stdFlow, dest
46
+ puts "\n Standard flow copied to #{dest}\n".green
47
+ end
48
+
49
+ end
50
+
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'release/gem'
4
+
5
+ puts "\n Standard GEM CLI release flow version #{Release::Gem::VERSION}\n".yellow
6
+
7
+ begin
8
+
9
+ Release::Gem.engine(:gem, root: Dir.getwd) do
10
+
11
+ # step 1 : run test
12
+ run_test(:rspec)
13
+
14
+ gem_cli_action do
15
+
16
+ # step 2 : check dependency
17
+ release_dependencies
18
+
19
+ # step 3 : build the gem
20
+ st, ver = build
21
+ if st
22
+ # step 4, push the gem to rubygems
23
+ push(version: ver)
24
+ install(version: ver)
25
+ end
26
+
27
+ end # gem_cli_action
28
+
29
+ vcs_cli_action do
30
+ @selVer = value(:selected_version)
31
+
32
+ # step 6 : commit vcs
33
+ commit
34
+
35
+ # step 7 : tag the source code
36
+ tag( tag: @selVer )
37
+
38
+ # step 8 : Push the source code
39
+ push
40
+
41
+ end # vcs_action block
42
+
43
+ end # Release::Gem::Engine block
44
+
45
+ puts "\n *** GEM standard release flow done!\n".green
46
+
47
+ rescue Release::Gem::Abort => ex
48
+ STDERR.puts "\n -- Aborted by user. Message was : #{ex.message}\n".red
49
+ rescue TTY::Reader::InputInterrupt => ex
50
+ rescue Exception => ex
51
+ STDERR.puts "\n -- Error thrown. Message was : #{ex.message}".red
52
+ end
53
+
54
+
55
+
56
+