gtlab 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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/Gitl.yml +42 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/gitl +8 -0
- data/gitl.gemspec +39 -0
- data/lib/Command.rb +70 -0
- data/lib/commands/branch.rb +2 -0
- data/lib/commands/create.rb +67 -0
- data/lib/commands/create_tag.rb +104 -0
- data/lib/commands/delete_tag.rb +98 -0
- data/lib/commands/diff.rb +2 -0
- data/lib/commands/forall.rb +2 -0
- data/lib/commands/init.rb +36 -0
- data/lib/commands/push.rb +2 -0
- data/lib/commands/review.rb +262 -0
- data/lib/commands/start.rb +116 -0
- data/lib/commands/status.rb +2 -0
- data/lib/commands/sync.rb +45 -0
- data/lib/config/gitl_config.rb +71 -0
- data/lib/config/work_space_config.rb +25 -0
- data/lib/git_ext.rb +120 -0
- data/lib/gitl.rb +8 -0
- data/lib/gitl/version.rb +3 -0
- data/lib/gitlab_ext.rb +26 -0
- data/lib/sub_command.rb +139 -0
- metadata +175 -0
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'sub_command'
|
2
|
+
|
3
|
+
|
4
|
+
module Gitl
|
5
|
+
|
6
|
+
class CreateTag < SubCommand
|
7
|
+
|
8
|
+
self.summary = '新建tag'
|
9
|
+
|
10
|
+
self.description = <<-DESC
|
11
|
+
指定分支上新建tag.
|
12
|
+
DESC
|
13
|
+
|
14
|
+
self.arguments = [
|
15
|
+
CLAide::Argument.new('branch', true, false),
|
16
|
+
CLAide::Argument.new('tag_name', true, false),
|
17
|
+
]
|
18
|
+
|
19
|
+
def self.options
|
20
|
+
[
|
21
|
+
["--force", "忽略tag是否存在,强制执行"],
|
22
|
+
].concat(super)
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(argv)
|
26
|
+
@branch = argv.shift_argument
|
27
|
+
@tag_name = argv.shift_argument
|
28
|
+
@force = argv.flag?('force')
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate!
|
33
|
+
super
|
34
|
+
if @branch.nil?
|
35
|
+
help! 'branch is required.'
|
36
|
+
end
|
37
|
+
if @tag_name.nil?
|
38
|
+
help! 'tag_name is required.'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def run
|
43
|
+
# api: https://www.rubydoc.info/gems/gitlab/toplevel
|
44
|
+
# document: https://narkoz.github.io/gitlab/cli
|
45
|
+
|
46
|
+
Gitlab.configure do |config|
|
47
|
+
# set an API endpoint
|
48
|
+
# API endpoint URL, default: ENV['GITLAB_API_ENDPOINT']
|
49
|
+
config.endpoint = self.gitl_config.gitlab.endpoint
|
50
|
+
|
51
|
+
# set a user private token
|
52
|
+
# user's private token or OAuth2 access token, default: ENV['GITLAB_API_PRIVATE_TOKEN']
|
53
|
+
config.private_token = self.gitl_config.gitlab.private_token
|
54
|
+
|
55
|
+
# user agent
|
56
|
+
config.user_agent = "gitl ruby gem[#{VERSION}"
|
57
|
+
end
|
58
|
+
|
59
|
+
self.gitl_config.projects.each do |project|
|
60
|
+
gitlab_project = gitlab_search_project(project.name)
|
61
|
+
info "find project #{gitlab_project.name} on #{gitlab_project.web_url}."
|
62
|
+
begin
|
63
|
+
tag = Gitlab.tag(gitlab_project.id, @tag_name)
|
64
|
+
rescue Gitlab::Error::NotFound => error
|
65
|
+
tag = nil
|
66
|
+
rescue Gitlab::Error::Error => error
|
67
|
+
raise(error)
|
68
|
+
end
|
69
|
+
|
70
|
+
if tag.nil?
|
71
|
+
Gitlab.create_tag(gitlab_project.id, @tag_name, @branch)
|
72
|
+
info "create tag '#{@tag_name}' success"
|
73
|
+
else
|
74
|
+
if @force
|
75
|
+
info "tag '#{@tag_name}' exist, skip."
|
76
|
+
else
|
77
|
+
help! "tag '#{@tag_name}' exist."
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
puts
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def gitlab_search_project(project_name)
|
86
|
+
projects = Gitlab.project_search(project_name)
|
87
|
+
if projects.size > 1
|
88
|
+
info "find #{projects.size} project named #{project_name}. you means which one?"
|
89
|
+
projects.each do |project|
|
90
|
+
print project.name + ' '
|
91
|
+
end
|
92
|
+
print "\n"
|
93
|
+
raise Error.new("find #{projects.size} project named #{project_name}")
|
94
|
+
|
95
|
+
elsif projects.size == 1
|
96
|
+
project = projects[0];
|
97
|
+
else
|
98
|
+
raise Error.new("can't find project named '#{project_name}'.")
|
99
|
+
end
|
100
|
+
project
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'sub_command'
|
2
|
+
|
3
|
+
|
4
|
+
module Gitl
|
5
|
+
|
6
|
+
class DeleteTag < SubCommand
|
7
|
+
|
8
|
+
self.summary = '删除tag'
|
9
|
+
|
10
|
+
self.description = <<-DESC
|
11
|
+
删除指定tag.
|
12
|
+
DESC
|
13
|
+
|
14
|
+
self.arguments = [
|
15
|
+
CLAide::Argument.new('tag_name', true, false),
|
16
|
+
]
|
17
|
+
|
18
|
+
def self.options
|
19
|
+
[
|
20
|
+
["--force", "忽略tag是否存在,强制执行"],
|
21
|
+
].concat(super)
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(argv)
|
25
|
+
@tag_name = argv.shift_argument
|
26
|
+
@force = argv.flag?('force')
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate!
|
31
|
+
super
|
32
|
+
if @tag_name.nil?
|
33
|
+
help! 'tag_name is required.'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def run
|
38
|
+
# api: https://www.rubydoc.info/gems/gitlab/toplevel
|
39
|
+
# document: https://narkoz.github.io/gitlab/cli
|
40
|
+
|
41
|
+
Gitlab.configure do |config|
|
42
|
+
# set an API endpoint
|
43
|
+
# API endpoint URL, default: ENV['GITLAB_API_ENDPOINT']
|
44
|
+
config.endpoint = self.gitl_config.gitlab.endpoint
|
45
|
+
|
46
|
+
# set a user private token
|
47
|
+
# user's private token or OAuth2 access token, default: ENV['GITLAB_API_PRIVATE_TOKEN']
|
48
|
+
config.private_token = self.gitl_config.gitlab.private_token
|
49
|
+
|
50
|
+
# user agent
|
51
|
+
config.user_agent = "gitl ruby gem[#{VERSION}"
|
52
|
+
end
|
53
|
+
|
54
|
+
info "ready delete tag '#{@tag_name}'.\n"
|
55
|
+
|
56
|
+
self.gitl_config.projects.each do |project|
|
57
|
+
gitlab_project = gitlab_search_project(project.name)
|
58
|
+
info "find project #{gitlab_project.name} on #{gitlab_project.web_url}."
|
59
|
+
|
60
|
+
begin
|
61
|
+
tag = Gitlab.delete_tag(gitlab_project.id, @tag_name)
|
62
|
+
rescue Gitlab::Error::NotFound => error
|
63
|
+
tag = nil
|
64
|
+
if @force
|
65
|
+
raise(error)
|
66
|
+
else
|
67
|
+
info "tag '#{@tag_name}' not found, skip."
|
68
|
+
end
|
69
|
+
rescue Gitlab::Error::Error => error
|
70
|
+
raise(error)
|
71
|
+
end
|
72
|
+
if tag
|
73
|
+
info "delete tag '#{@tag_name}' success.\n"
|
74
|
+
end
|
75
|
+
puts
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def gitlab_search_project(project_name)
|
80
|
+
projects = Gitlab.project_search(project_name)
|
81
|
+
if projects.size > 1
|
82
|
+
info "find #{projects.size} project named #{project_name}. you means which one?"
|
83
|
+
projects.each do |project|
|
84
|
+
print project.name + ' '
|
85
|
+
end
|
86
|
+
print "\n"
|
87
|
+
raise Error.new("find #{projects.size} project named #{project_name}")
|
88
|
+
|
89
|
+
elsif projects.size == 1
|
90
|
+
project = projects[0];
|
91
|
+
else
|
92
|
+
raise Error.new("can't find project named '#{project_name}'.")
|
93
|
+
end
|
94
|
+
project
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'sub_command'
|
2
|
+
|
3
|
+
module Gitl
|
4
|
+
|
5
|
+
class Init < SubCommand
|
6
|
+
|
7
|
+
self.summary = '根据yml配置,更新代码'
|
8
|
+
|
9
|
+
self.description = <<-DESC
|
10
|
+
根据yml配置,更新代码.
|
11
|
+
DESC
|
12
|
+
|
13
|
+
def run
|
14
|
+
mutex = Mutex.new
|
15
|
+
threads = []
|
16
|
+
self.gitl_config.projects.each do |project|
|
17
|
+
t = Thread.new do
|
18
|
+
project_path = File.expand_path(project.name, './')
|
19
|
+
if File.exist?(project_path)
|
20
|
+
mutex.synchronize do
|
21
|
+
info project.name + ' exists, skip.'
|
22
|
+
end
|
23
|
+
else
|
24
|
+
Git.clone_without_env(project.git, project.name, :path => './')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
threads << t
|
28
|
+
end
|
29
|
+
threads.each do |t|
|
30
|
+
t.join
|
31
|
+
end
|
32
|
+
puts "#{self.gitl_config.projects.size} projects init success.".green
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,262 @@
|
|
1
|
+
require 'sub_command'
|
2
|
+
require 'gitlab_ext'
|
3
|
+
|
4
|
+
module Gitl
|
5
|
+
class Review < SubCommand
|
6
|
+
|
7
|
+
self.summary = '创建对应工作分支,并同步到gitlab.'
|
8
|
+
|
9
|
+
self.description = <<-DESC
|
10
|
+
创建对应工作分支,并同步到gitlab.
|
11
|
+
DESC
|
12
|
+
|
13
|
+
# self.arguments = [
|
14
|
+
# CLAide::Argument.new('working_branch', false, false),
|
15
|
+
# CLAide::Argument.new('remote_branch', false, false),
|
16
|
+
# ]
|
17
|
+
|
18
|
+
def self.options
|
19
|
+
[
|
20
|
+
["--assignee=[user name]", "指定review用户名称"],
|
21
|
+
["--title", "merge request标题"],
|
22
|
+
["--show-diff", "review前是否显示变更"],
|
23
|
+
].concat(super)
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(argv)
|
27
|
+
# @working_branch = argv.shift_argument
|
28
|
+
# @remote_branch = argv.shift_argument
|
29
|
+
@assignee = argv.option('assignee')
|
30
|
+
@title = argv.option('title')
|
31
|
+
@show_diff = argv.flag?('show-diff')
|
32
|
+
super
|
33
|
+
end
|
34
|
+
|
35
|
+
def validate!
|
36
|
+
super
|
37
|
+
# if @working_branch.nil?
|
38
|
+
# help! 'working_branch is required.'
|
39
|
+
# end
|
40
|
+
# if @remote_branch.nil?
|
41
|
+
# help! 'remote_branch is required.'
|
42
|
+
# end
|
43
|
+
# if @assignee.nil?
|
44
|
+
# help! 'assignee is required.'
|
45
|
+
# end
|
46
|
+
end
|
47
|
+
|
48
|
+
def run_in_workspace
|
49
|
+
|
50
|
+
@working_branch = self.workspace_config.workspace_branch
|
51
|
+
@remote_branch = self.workspace_config.remote_branch
|
52
|
+
|
53
|
+
# api: https://www.rubydoc.info/gems/gitlab/toplevel
|
54
|
+
# document: https://narkoz.github.io/gitlab/cli
|
55
|
+
|
56
|
+
Gitlab.configure do |config|
|
57
|
+
# set an API endpoint
|
58
|
+
# API endpoint URL, default: ENV['GITLAB_API_ENDPOINT']
|
59
|
+
config.endpoint = self.gitl_config.gitlab.endpoint
|
60
|
+
|
61
|
+
# set a user private token
|
62
|
+
# user's private token or OAuth2 access token, default: ENV['GITLAB_API_PRIVATE_TOKEN']
|
63
|
+
config.private_token = self.gitl_config.gitlab.private_token
|
64
|
+
|
65
|
+
# user agent
|
66
|
+
config.user_agent = "gitl ruby gem[#{VERSION}"
|
67
|
+
end
|
68
|
+
|
69
|
+
user = nil
|
70
|
+
if !@assignee.nil?
|
71
|
+
user = gitlab_search_user(@assignee)
|
72
|
+
end
|
73
|
+
|
74
|
+
self.gitl_config.projects.each_with_index do |project, index|
|
75
|
+
project_path = File.expand_path(project.name, './')
|
76
|
+
if File.exist?(project_path)
|
77
|
+
remote = 'origin'
|
78
|
+
info "Create branch '#{@working_branch}' for project '#{project.name}'"
|
79
|
+
g = Git.open(project_path)
|
80
|
+
else
|
81
|
+
g = Git.clone(project.git, project.name, :path => './')
|
82
|
+
end
|
83
|
+
|
84
|
+
gitlab_project = gitlab_search_project(project.name)
|
85
|
+
info "Find project #{gitlab_project.name} on #{gitlab_project.web_url}."
|
86
|
+
|
87
|
+
unless g.is_remote_branch?(@working_branch)
|
88
|
+
raise Error.new("Branch '#{@working_branch}' not exist in remote '#{remote}'.")
|
89
|
+
end
|
90
|
+
|
91
|
+
unless g.is_remote_branch?(@remote_branch)
|
92
|
+
raise Error.new("Branch '#{@remote_branch}' not exist in remote '#{remote}'.")
|
93
|
+
end
|
94
|
+
|
95
|
+
g.checkout(@working_branch)
|
96
|
+
# 更新本地代码
|
97
|
+
g.fetch(remote, :p => true, :t => true)
|
98
|
+
g.pull("origin", @working_branch)
|
99
|
+
g.pull("origin", @remote_branch)
|
100
|
+
# push到origin
|
101
|
+
g.push(remote, @working_branch)
|
102
|
+
|
103
|
+
compare_response = Gitlab.compare(gitlab_project.id, @remote_branch, @working_branch);
|
104
|
+
if compare_response.commits.size >= 1
|
105
|
+
if @show_diff
|
106
|
+
puts "\ncommits"
|
107
|
+
compare_response.commits.each_with_index do |commit, index|
|
108
|
+
unless index == 0
|
109
|
+
puts ""
|
110
|
+
end
|
111
|
+
puts " #{index} id:" + commit["id"]
|
112
|
+
puts " author:" + commit["author_name"]
|
113
|
+
puts " create at: " + commit["created_at"]
|
114
|
+
puts " title: " + commit["title"]
|
115
|
+
end
|
116
|
+
puts ""
|
117
|
+
end
|
118
|
+
else
|
119
|
+
info "Can't find new commit on #{@working_branch} to #{@remote_branch} in project #{project.name}."
|
120
|
+
puts
|
121
|
+
next
|
122
|
+
end
|
123
|
+
|
124
|
+
if compare_response.diffs.size >= 1
|
125
|
+
if @show_diff
|
126
|
+
puts "Diffs"
|
127
|
+
compare_response.diffs.each do |diff|
|
128
|
+
if diff["new_file"]
|
129
|
+
puts " created " + diff["new_path"]
|
130
|
+
elsif diff["renamed_file"]
|
131
|
+
puts " renamed " + diff["old_path"] + "=>" + diff["new_path"]
|
132
|
+
elsif diff["deleted_file"]
|
133
|
+
puts " deleted" + diff["old_path"]
|
134
|
+
else
|
135
|
+
puts " edited " + diff["new_path"]
|
136
|
+
end
|
137
|
+
|
138
|
+
diff = diff["diff"];
|
139
|
+
lines = diff.split("\n")
|
140
|
+
lines.each do |line|
|
141
|
+
puts " " + line
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|
146
|
+
else
|
147
|
+
info "Can't find diff between #{@working_branch} and #{@remote_branch} in project #{project.name}."
|
148
|
+
puts
|
149
|
+
next
|
150
|
+
end
|
151
|
+
|
152
|
+
if user.nil?
|
153
|
+
users = gitlab_get_team_members(gitlab_project.id)
|
154
|
+
begin
|
155
|
+
info "\nSelect user name or index for review."
|
156
|
+
input_user = STDIN.gets.chomp
|
157
|
+
if input_user =~ /[[:digit:]]/
|
158
|
+
user = users[input_user.to_i - 1]
|
159
|
+
else
|
160
|
+
user = gitlab_search_user(input_user)
|
161
|
+
end
|
162
|
+
if user.nil?
|
163
|
+
error "Can not found user '#{input_user}'."
|
164
|
+
else
|
165
|
+
info "Assign to #{user.username}(#{user.name})"
|
166
|
+
end
|
167
|
+
end until !user.nil?
|
168
|
+
end
|
169
|
+
|
170
|
+
if @title.nil? || @title.empty?
|
171
|
+
begin
|
172
|
+
info "\nInput merge request title for project '#{project.name}'"
|
173
|
+
@title = STDIN.gets.chomp
|
174
|
+
end until @title.length > 0
|
175
|
+
end
|
176
|
+
|
177
|
+
# 总共 0 (差异 0),复用 0 (差异 0)
|
178
|
+
# remote:
|
179
|
+
# remote: To create a merge request for dev-v3.9.0-luobin, visit:
|
180
|
+
# remote: http://git.tianxiao100.com/tianxiao-ios/tianxiao/tianxiao-base-iphone-sdk/merge_requests/new?merge_request%5Bsource_branch%5D=dev-v3.9.0-luobin
|
181
|
+
# remote:
|
182
|
+
# To http://git.tianxiao100.com/tianxiao-ios/tianxiao/tianxiao-base-iphone-sdk.git
|
183
|
+
# * [new branch] dev-v3.9.0-luobin -> dev-v3.9.0-luobin
|
184
|
+
|
185
|
+
begin
|
186
|
+
merge_request = Gitlab.create_merge_request(gitlab_project.id, @title,
|
187
|
+
{ source_branch: @working_branch, target_branch: @remote_branch, assignee_id:user ? user.id : "" })
|
188
|
+
info "Create merge request for #{project.name} success. see detail url:#{merge_request.web_url}"
|
189
|
+
if !Gem.win_platform?
|
190
|
+
`open -a "/Applications/Google Chrome.app" '#{merge_request.web_url}/diffs'`
|
191
|
+
exitstatus = $?.exitstatus
|
192
|
+
if exitstatus != 0
|
193
|
+
raise Error.new("open chrome failed.")
|
194
|
+
else
|
195
|
+
if index != self.gitl_config.projects.length - 1
|
196
|
+
info "Please review diff, then input any to continue."
|
197
|
+
STDIN.gets.chomp
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
rescue Gitlab::Error::Conflict => error
|
202
|
+
# merge exists
|
203
|
+
info "Merge request from '#{@working_branch}' to '#{@remote_branch}' exist."
|
204
|
+
rescue Gitlab::Error::Error => error
|
205
|
+
raise(error)
|
206
|
+
end
|
207
|
+
puts
|
208
|
+
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def gitlab_search_user(assignee)
|
213
|
+
users = Gitlab.user_search(assignee)
|
214
|
+
if users.size > 1
|
215
|
+
info "Find more than one user. you means which one?"
|
216
|
+
users.each do |user|
|
217
|
+
print user.name + ' '
|
218
|
+
end
|
219
|
+
info ""
|
220
|
+
raise Error.new("Find #{users.size} user named #{project.name}")
|
221
|
+
elsif users.size == 1
|
222
|
+
user = users[0]
|
223
|
+
else
|
224
|
+
raise Error.new("Can't find user #{assignee}.")
|
225
|
+
end
|
226
|
+
user
|
227
|
+
end
|
228
|
+
|
229
|
+
def gitlab_search_project(project_name)
|
230
|
+
projects = Gitlab.project_search(project_name)
|
231
|
+
if projects.size > 1
|
232
|
+
info "Find #{projects.size} project named #{project_name}. you means which one?"
|
233
|
+
projects.each do |project|
|
234
|
+
print project.name + ' '
|
235
|
+
end
|
236
|
+
print "\n"
|
237
|
+
raise Error.new("Find #{projects.size} project named #{project_name}")
|
238
|
+
|
239
|
+
elsif projects.size == 1
|
240
|
+
project = projects[0];
|
241
|
+
else
|
242
|
+
raise Error.new("Can't find project named '#{project_name}'.")
|
243
|
+
end
|
244
|
+
project
|
245
|
+
end
|
246
|
+
|
247
|
+
def gitlab_get_team_members(project_id)
|
248
|
+
users = Gitlab.project_usesrs(project_id).delete_if { |user|
|
249
|
+
user.username == 'root'
|
250
|
+
}
|
251
|
+
if users.size > 0
|
252
|
+
info "Find user to assign."
|
253
|
+
users.each_with_index do |user, index|
|
254
|
+
puts "#{index + 1}、#{user.username}(#{user.name})".green
|
255
|
+
end
|
256
|
+
else
|
257
|
+
raise Error.new("Can't find members in project '#{project_id}''.")
|
258
|
+
end
|
259
|
+
users
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|