fgi 1.0.2 → 1.1.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: 2c10109eb480ab557f79d477ff770b7b4113d079
4
- data.tar.gz: a718badc264ab8b9483e11ec76082db9a04aac99
3
+ metadata.gz: 01ff812f6d7df394c97c84fe04677f1421726d96
4
+ data.tar.gz: d8888bd13fd3f3b38ad99d3dc4ca659d438def4d
5
5
  SHA512:
6
- metadata.gz: 7eab634762636cc11025a56296c9b20e3e8d767935c245db69acefc7313b8ed02646d1660737343d50bc71d75ac128d2cb775127777c6166745281ba78633a44
7
- data.tar.gz: ce9f2d259e89d34e3ee9fb822d0b0dfa6516f71cf91b74d3a5f51dbffed28aea0ddf7077125d4cf567f789506586a3a390365b01992fe6ff14f77489b85cd12e
6
+ metadata.gz: a2a5e66b748bf7f182b2b0c4757e575bcad60f8a04016bbb9d91634e228415831a4bf3e5d40d0fa7982b98172c3210a01c1058e558277c7c83559dd4ac6898a3
7
+ data.tar.gz: 5a7965629498624bfd1f66a50708c9e9fc1da3ec35319e205baad5f2e976694989fafd01cbaef1ac7c1919494d53a4ca6443ab45314fe2f6cb519c51ad7231b3
data/bin/fgi CHANGED
@@ -17,20 +17,32 @@ options_parser = OptionParser.new do |fgi|
17
17
  fgi.separator ' config : run the FGI configurator.'
18
18
  fgi.separator ' token [TOKEN] : define the new user token.'
19
19
  fgi.separator ' new [ISSUE_NAME] : create the issue with the given name.'
20
+ fgi.separator ' fix : fix the current issue.'
20
21
  fgi.separator ' ... more comming soon ...'
21
22
  fgi.separator ''
22
23
  fgi.separator 'Options'
23
24
 
25
+ fgi.on('-h', '--help', 'Display the FGI manual')
26
+
27
+ fgi.on('-v', '--version', 'Display the FGI version') do
28
+ puts "FGI #{Fgi::VERSION}"
29
+ exit!
30
+ end
31
+
24
32
  fgi.on('-e', '--estimate [ESTIMATION]', 'How many time do you think you will spend on this issue ? (example: 1d13h37m05s)') do |estimate|
25
33
  options[:estimate] = estimate
26
34
  end
27
35
 
28
- fgi.on('-l', '--later', 'Tell FGI that you anly want to create an issue but not to create and switch branch.') do
36
+ fgi.on('-l', '--later', 'Tell FGI that you only want to create an issue but not to create and switch branch.') do
29
37
  options[:later] = true
30
38
  end
31
39
 
32
- fgi.on('-h', '--help', 'Display the FGI manual') do
33
- puts options_parser
40
+ fgi.on('-p', '--prefix [PREFIX]', 'Tell FGI that you want to add a prefix to the branch name.') do |prefix|
41
+ options[:prefix] = prefix
42
+ end
43
+
44
+ fgi.on('-m', '--fix-message [MESSAGE]', %q(Add a custom message with the basic 'Fix #ID')) do |message|
45
+ options[:fix_message] = message
34
46
  end
35
47
  end
36
48
  options_parser.parse!
@@ -50,15 +62,17 @@ when 'config'
50
62
  Fgi::Configuration.new_config
51
63
  when 'new'
52
64
  Fgi.configured?
53
- if argv[1].start_with?('-')
65
+ if !argv[1].nil? && argv[1].start_with?('-')
54
66
  puts %q(You can't begin your issue's title with '-')
55
67
  exit!
56
68
  end
57
69
  title = get_full_issue_title(argv)
58
- Fgi::GitService.create_issue(title: title, options: options)
70
+ Fgi::GitService.new_issue(title: title, options: options)
59
71
  when 'token'
60
72
  Fgi.configured?
61
73
  Fgi::Tokens.add_token(argv[1])
74
+ when 'fix'
75
+ Fgi::GitService.fix_issue(options)
62
76
  else
63
77
  puts options_parser
64
78
  end
data/lib/fgi.rb CHANGED
@@ -6,6 +6,7 @@ module Fgi
6
6
  require 'json'
7
7
  require 'yaml'
8
8
  require 'uri'
9
+ require 'cgi'
9
10
 
10
11
  require_relative 'fgi/git_services/gitlab'
11
12
  require_relative 'fgi/http_requests'
@@ -13,19 +14,28 @@ module Fgi
13
14
  require_relative 'fgi/configuration'
14
15
  require_relative 'fgi/git_service'
15
16
 
16
- # Define const variables if fgi config files exists
17
+ VERSION = '1.1.1'.freeze
18
+
19
+ # Add FGI user's current issues to the gitignore
20
+ if `cat .gitignore | grep '.current_issues.fgi.yml'`.empty?
21
+ File.open('.gitignore', 'a') { |f| f.write("\n.current_issues.fgi.yml\n") }
22
+ end
23
+
24
+ ISSUES = YAML.load_file('.current_issues.fgi.yml') if File.exist?('.current_issues.fgi.yml')
25
+ # Define const variables if fgi config files exists
17
26
  # otherwise ask for configuration
18
- if File.exists?('.config.fgi.yml')
27
+ if File.exist?('.config.fgi.yml')
19
28
  CONFIG = YAML.load_file('.config.fgi.yml')
20
29
  git_service = CONFIG[:git_service_class].new
21
- if File.exists?("#{Dir.home}/.tokens.fgi.yml")
22
- TOKEN = YAML.load_file("#{Dir.home}/.tokens.fgi.yml")[git_service.to_sym]
30
+ if File.exist?("#{Dir.home}/.tokens.fgi.yml")
31
+ TOKEN = YAML.load_file("#{Dir.home}/.tokens.fgi.yml")[git_service.to_sym][CONFIG[:url]]
23
32
  end
24
33
  end
25
34
 
26
35
  def self.configured?
27
- return if File.exists?('.config.fgi.yml')
36
+ return if File.exist?('.config.fgi.yml')
28
37
  puts "\nThere is no FGI configuration file on this project. Please run 'fgi config'.\n\n"
29
38
  exit!
30
39
  end
40
+
31
41
  end
@@ -2,6 +2,7 @@
2
2
  module Fgi
3
3
  class Configuration
4
4
  class << self
5
+
5
6
  include HttpRequests
6
7
 
7
8
  # Launch the process to create the fresh project fgi config file
@@ -21,7 +22,6 @@ module Fgi
21
22
  # INITIALIZERS #
22
23
  # -------------------------- #
23
24
 
24
-
25
25
  # The hash that will contain the project's fgi configuration to save as yml
26
26
  # It will contain :
27
27
  # :url
@@ -38,18 +38,17 @@ module Fgi
38
38
  # TODO - HARD REFECTO NEEDED HERE...
39
39
  git_service = config[:git_service_class].new(config: config)
40
40
  config[:git_service] = git_service.to_sym
41
- user_token = save_user_token(git_service)
41
+ user_token = save_user_token(config: config, git_service: git_service)
42
42
  project_name_and_id = define_project_name_and_id(git_service, user_token)
43
43
  config = config.merge(project_name_and_id)
44
44
  git_service = config[:git_service_class].new(config: config)
45
45
  config[:default_branch] = define_default_branch(git_service, user_token)
46
46
 
47
-
48
47
  # -------------------------- #
49
48
  # CREATORS #
50
49
  # -------------------------- #
51
50
 
52
- Fgi::Tokens.create_user_tokens_file(config[:git_service], user_token)
51
+ Fgi::Tokens.create_user_tokens_file(config: config, git_service: git_service, token: user_token)
53
52
  create_fgi_config_file(config)
54
53
  end
55
54
 
@@ -57,21 +56,19 @@ module Fgi
57
56
 
58
57
  # Check if we are in a git repository. Exit FGI if not.
59
58
  def git_directory?
60
- unless Dir.exists?('.git')
61
- puts 'You are not in a git project repository.'
62
- exit!
63
- end
59
+ return if Dir.exist?('.git')
60
+ puts 'You are not in a git project repository.'
61
+ exit!
64
62
  end
65
63
 
66
64
  # Check if FGI has already been configured. Exit FGI if not.
67
65
  def already_configured?
68
- if File.exists?('.config.fgi.yml')
69
- puts 'There is already a FGI config on this project.'
70
- exit!
71
- end
66
+ return unless File.exist?('.config.fgi.yml')
67
+ puts 'There is already a FGI config on this project.'
68
+ exit!
72
69
  end
73
70
 
74
- # Ask the user to shoose the project's Git service
71
+ # Ask the user to shoose the project's Git service
75
72
  # @return [Class] the project's Git service class
76
73
  def define_git_service
77
74
  puts "\nPlease insert the number of the used Git service :"
@@ -81,9 +78,9 @@ module Fgi
81
78
  git_services = Fgi::GitService.services
82
79
  # Display theses services to let the user choose the project's one
83
80
  git_services.each_with_index do |service, index|
84
- puts "#{index+1} : #{service.capitalize}"
81
+ puts "#{index + 1} : #{service.capitalize}"
85
82
  end
86
- puts "... More soon ..."
83
+ puts '... More soon ...'
87
84
 
88
85
  begin
89
86
  input = STDIN.gets.chomp
@@ -91,15 +88,15 @@ module Fgi
91
88
  # Convert the string input to an integer
92
89
  input = input.to_i
93
90
  # If the input isn't out of range...
94
- if (1..git_services.count).include?(input)
91
+ if (1..git_services.count).cover?(input)
95
92
  # Set a variable with the Git service name for displays
96
- @git_service = git_services[input-1].capitalize
93
+ @git_service = git_services[input - 1].capitalize
97
94
  Fgi::GitServices.const_get(@git_service)
98
95
  else
99
96
  puts "\nSorry, the option is out of range. Try again :"
100
97
  define_git_service
101
98
  end
102
- rescue Interrupt => int
99
+ rescue Interrupt
103
100
  exit!
104
101
  end
105
102
  end
@@ -116,18 +113,18 @@ module Fgi
116
113
  exit! if input == 'quit'
117
114
  # force scheme if not specified
118
115
  # TODO - Find a way to clear this... Find the correct scheme.
119
- input = if input.start_with?('gitlab.com')
120
- "https://#{input}"
121
- elsif !input.start_with?('http://', 'https://')
122
- "http://#{input}"
123
- end
116
+ if input.start_with?('gitlab.com')
117
+ input = "https://#{input}"
118
+ elsif !input.start_with?('http://', 'https://')
119
+ input = "http://#{input}"
120
+ end
124
121
  # Call the entered url to know if it exist or not.
125
122
  # If not, would raise an exception
126
123
  get(url: input)
127
124
  input
128
- rescue Interrupt => int
125
+ rescue Interrupt
129
126
  exit!
130
- rescue Exception => e
127
+ rescue Exception
131
128
  puts "\nOops, seems to be a bad url. Try again or quit (quit)"
132
129
  save_git_url
133
130
  end
@@ -136,10 +133,9 @@ module Fgi
136
133
  # Ask for the user for his Git service token
137
134
  # @param git_service [Class] the current project's git service class
138
135
  # @return [String] the user Git service token
139
- def save_user_token(git_service)
140
- token = Fgi::Tokens.get_token(git_service)
136
+ def save_user_token(config:, git_service:)
137
+ token = Fgi::Tokens.get_token(config: config, git_service: git_service)
141
138
  return token unless token.nil?
142
- save_user_token(git_service)
143
139
  end
144
140
 
145
141
  # Ask the user to search for the project and to select the correct one.
@@ -161,7 +157,7 @@ module Fgi
161
157
  if response[:status] == '200' && !response[:body].empty?
162
158
  puts "\nFound #{response[:body].count} match(es):"
163
159
  response[:body].each_with_index do |project, index|
164
- puts "#{index+1} - #{project['name_with_namespace']}"
160
+ puts "#{index + 1} - #{project['name_with_namespace']}"
165
161
  end
166
162
 
167
163
  puts "\nPlease insert the number of the current project :"
@@ -174,10 +170,10 @@ module Fgi
174
170
 
175
171
  else
176
172
  puts "\nOops, we couldn't find a project called #{input}. Try again or quit (quit) :"
177
- puts '-------------------------------------------------------------------'+('-'*input.length) # Don't be upset, i'm a perfectionist <3
173
+ puts '-------------------------------------------------------------------' + ('-' * input.length) # Don't be upset, i'm a perfectionist <3
178
174
  define_project_name_and_id(git_service, user_token)
179
175
  end
180
- rescue Interrupt => int
176
+ rescue Interrupt
181
177
  exit!
182
178
  end
183
179
  end
@@ -186,23 +182,21 @@ module Fgi
186
182
  puts "\nPlease define the default project branch :"
187
183
  puts '------------------------------------------'
188
184
 
189
- url = "#{git_service.routes[:branches]}"
185
+ url = git_service.routes[:branches]
190
186
  response = get(url: url, headers: { git_service.token_header => user_token })
187
+ return unless response[:status] == '200' && !response[:body].empty?
191
188
 
192
- if response[:status] == '200' && !response[:body].empty?
193
- begin
194
- response[:body].each_with_index do |branch, index|
195
- puts "#{index+1} - #{branch['name']}"
196
- end
197
-
198
- puts "\nPlease insert the number of the default project branch :"
199
- puts '--------------------------------------------------------'
200
- input = validate_choice(response[:body])
201
- response[:body][input - 1]['name']
202
-
203
- rescue Interrupt => int
204
- exit!
189
+ begin
190
+ response[:body].each_with_index do |branch, index|
191
+ puts "#{index + 1} - #{branch['name']}"
205
192
  end
193
+
194
+ puts "\nPlease insert the number of the default project branch :"
195
+ puts '--------------------------------------------------------'
196
+ input = validate_choice(response[:body])
197
+ response[:body][input - 1]['name']
198
+ rescue Interrupt
199
+ exit!
206
200
  end
207
201
  end
208
202
 
@@ -210,7 +204,7 @@ module Fgi
210
204
  input = STDIN.gets.chomp
211
205
  exit! if input == 'quit'
212
206
  input = input.to_i
213
- if (1..response_body.count).include?(input)
207
+ if (1..response_body.count).cover?(input)
214
208
  input
215
209
  else
216
210
  puts "\nSorry, the option is out of range. Try again :"
@@ -2,120 +2,227 @@
2
2
  module Fgi
3
3
  class GitService
4
4
  class << self
5
+
5
6
  include HttpRequests
6
7
 
8
+ # @return [Array<String>] an array containing all the git services available.
7
9
  def services
8
10
  services = []
9
11
  Dir.entries("#{File.dirname(__FILE__)}/git_services").each do |service|
10
- services << service.gsub(/.rb/, '').to_sym unless %w(. ..).include?(service)
12
+ services << service.gsub(/.rb/, '').to_sym unless %w[. ..].include?(service)
11
13
  end
12
14
  services
13
15
  end
14
16
 
15
- def create_issue(title: title, options: {})
17
+ # All the process initiated by the issue creation
18
+ # => Create issue
19
+ # => Create a new branch from the default one
20
+ # => Set the issue estimation time
21
+ # @param title [String] the issue title
22
+ # @param options [Hash] the options given by the user in the command line
23
+ def new_issue(title:, options: {})
16
24
  git_service = CONFIG[:git_service_class].new
17
25
  title = get_issue_title if title.nil?
18
- description = get_issue_description
19
-
20
- headers = { git_service.token_header => TOKEN, 'Content-Type' => 'application/json' }
21
- url_with_querystring = "#{git_service.routes[:issues]}?title=#{URI.encode(title)}&description=#{URI.encode(description)}"
22
-
23
- response = post(url: url_with_querystring, headers: headers)
24
- response_body = JSON.parse(response[:body])
25
-
26
- post_issue_display(response_body)
26
+ response = create_issue(title: title, git_service: git_service)
27
27
 
28
28
  if CONFIG[:default_branch].nil?
29
29
  puts "\n/!\\ FGI IS NOT UP-TO-DATE /!\\"
30
30
  puts 'We are not able to create and switch you to the new branch.'
31
31
  puts 'Delete .config.fgi.yml and reconfigure fgi by running `fgi config`'
32
- else
33
- create_new_branch(title) unless response_body['iid'].nil? || options[:later]
32
+ elsif !response['iid'].nil?
33
+ branch_name = snakify(title)
34
+ branch_name = "#{options[:prefix]}/#{branch_name}" unless options[:prefix].nil?
35
+ save_issue(branch: branch_name, id: response['iid'], title: response['title'].tr("'", ' '))
36
+ create_branch(branch_name) unless options[:later]
37
+ set_issue_estimation(
38
+ issue_id: response['iid'],
39
+ estimation: options[:estimate],
40
+ git_service: git_service
41
+ )
34
42
  end
43
+ end
35
44
 
36
- unless options[:estimate].nil?
37
- # Since GitLab version isn't up to date, we should be able to add estimations in issues comments (/estimate)
38
- url_with_querystring = "#{git_service.routes[:issues]}/#{response_body['iid']}/time_estimate?duration=#{options[:estimate]}"
39
- response = post(url: url_with_querystring, headers: headers)
40
- # GitLab sucks sometimes... This API is an example
41
- begin
42
- response_body = JSON.parse(response[:body])
43
- rescue Exception => e
44
- response_body = response[:body]
45
+ # All the process initiated by the issue fix
46
+ # => Commiting with a 'Fix #<id>' message
47
+ # => Pushing the current branch to the remote repo
48
+ # => Return to the default project branch
49
+ # @param options [Hash] the options given by the user in the command line
50
+ def fix_issue(options)
51
+ current_branch = `git branch | grep '*'`.gsub('* ', '').chomp
52
+ if ISSUES[current_branch].nil?
53
+ puts "We could not find any issues to fix on your current branch (#{current_branch})."
54
+ exit!
55
+ end
56
+ git_remote = ask_for_remote
57
+ `git add .`
58
+ puts "Are you sure to want to close the issue #{ISSUES[current_branch][:title]} ?"
59
+ begin
60
+ input = STDIN.gets.chomp
61
+ if %w[y yes].include?(input)
62
+ commit_message = "Fix ##{ISSUES[current_branch][:id]}"
63
+ commit_message += " - #{options[:fix_message]}" unless options[:fix_message].nil?
64
+ `git commit -a --allow-empty -m '#{commit_message}'`
65
+ `git push #{git_remote} HEAD`
66
+ `git checkout #{CONFIG[:default_branch]}` # Be sure to be on the default branch.
67
+ remove_issue(current_branch)
68
+ puts "Congrat's ! You're now back to work on the default branch (#{CONFIG[:default_branch]})"
45
69
  end
46
-
47
- post_estimation_display(response_body, options[:estimate])
70
+ rescue Interrupt
71
+ puts %q"Why did you killed me ? :'("
72
+ exit!
48
73
  end
49
74
  end
50
75
 
51
- def create_new_branch(issue_title)
52
- branch_name = snakecase(issue_title)
53
- unless %x(git status -s).empty?
54
- begin
55
- puts "\nThere are unsaved changes on your current branch."
56
- puts "Do you want to see them ? (y/n)"
57
- puts '-------------------------------'
58
- input = STDIN.gets.chomp
59
- system('git diff') if %w[y yes].include?(input)
60
-
61
- puts "\nDo you want to COMMIT theses changes ? (y/n)"
62
- puts '--------------------------------------------'
63
- input = STDIN.gets.chomp
64
- if %w[y yes].include?(input)
65
- commit_changes
66
- else
67
- stash_changes
68
- end
69
-
70
- rescue Interrupt => int
71
- puts %q"Why did you killed me ? :'("
72
- exit!
76
+ private
77
+
78
+ def ask_for_remote
79
+ remotes = `git remote`.split("\n")
80
+ return remotes.first if remotes.count == 1
81
+
82
+ puts "\nHere are your remotes :"
83
+ remotes.each_with_index do |remote, index|
84
+ puts "#{index + 1} - #{remote}"
85
+ end
86
+
87
+ begin
88
+ puts "\nPlease insert the number of the remote to use :"
89
+ puts '-----------------------------------------------'
90
+ input = STDIN.gets.chomp
91
+ exit! if input == 'quit'
92
+ input = input.to_i
93
+ if (1..remotes.count).cover?(input)
94
+ remotes[input-1]
95
+ else
96
+ puts "\nSorry, the option is out of range. Try again :"
97
+ ask_for_remote
73
98
  end
99
+ rescue Interrupt
100
+ puts %q"Why did you killed me ? :'("
101
+ exit!
74
102
  end
75
- %x(git checkout #{CONFIG[:default_branch]}) # Be sure to be on the default branch.
76
- from = %x(git branch | grep '*').gsub('* ', '').chomp
77
- %x(git pull origin HEAD) # Be sure to get the remote changes locally.
78
- %x(git checkout -b #{branch_name}) # Create the new branch.
79
- to = %x(git branch | grep '*').gsub('* ', '').chomp
80
- puts "\nYou are now working on branch #{to} created from #{from} !"
81
103
  end
82
104
 
83
- private
105
+ # Save the current user's FGI created issue in the gitignored file 'current_issue.fgi.yml'
106
+ # @param id [Integer] the current issue id
107
+ # @param title [String] the current issue name
108
+ def save_issue(branch:, id:, title:)
109
+ if File.exist?('.current_issues.fgi.yml')
110
+ issues = YAML.load_file('.current_issues.fgi.yml')
111
+ issues[branch] = { id: id, title: title }
112
+ else
113
+ issues = {
114
+ branch => {
115
+ id: id,
116
+ title: title
117
+ }
118
+ }
119
+ end
120
+ # Shouldn't we define some access restrictions on this file ?
121
+ File.open('.current_issues.fgi.yml', 'w') { |f| f.write(issues.to_yaml) }
122
+ end
123
+
124
+ def remove_issue(branch)
125
+ issues = YAML.load_file('.current_issues.fgi.yml')
126
+ issues.delete(branch) unless ISSUES[branch].nil?
127
+ File.open('.current_issues.fgi.yml', 'w') { |f| f.write(issues.to_yaml) }
128
+ end
129
+
130
+ # TODO, Make sure it works for all git services
131
+ # The method to set the estimation time to resolve the issue
132
+ # @param issue_id [Integer] the issue id to set its estimation time
133
+ # @param estimation [String] the estimation time given by the user
134
+ # @param git_service [Class] the git service class to use for this project
135
+ def set_issue_estimation(issue_id:, estimation:, git_service:)
136
+ return if estimation.nil?
137
+ # Since GitLab version isn't up to date, we should be able
138
+ # to add estimations in issues comments (/estimate)
139
+ url_with_querystring = "#{git_service.routes[:issues]}/#{issue_id}/time_estimate?duration=#{estimation}"
140
+ response = post(url: url_with_querystring, headers: headers)
141
+ # GitLab sucks sometimes... This API is an example
142
+ begin
143
+ response_body = JSON.parse(response[:body])
144
+ rescue Exception
145
+ response_body = response[:body]
146
+ end
147
+ post_estimation_display(response_body['human_time_estimate'], estimation)
148
+ end
149
+
150
+ # TODO, Make sure it works for all git services
151
+ # The method used to create issues
152
+ # @param title [String] the issue title
153
+ # @param git_service [Class] the git service class to use for this project
154
+ # @return [Boolean] true if the issue has been created, false otherwise
155
+ def create_issue(title:, git_service:)
156
+ description = get_issue_description
157
+
158
+ headers = { git_service.token_header => TOKEN, 'Content-Type' => 'application/json' }
159
+ url_with_querystring = "#{git_service.routes[:issues]}?title=#{CGI.escape(title)}&description=#{CGI.escape(description)}"
160
+
161
+ response = post(url: url_with_querystring, headers: headers)
162
+ response_body = JSON.parse(response[:body])
163
+
164
+ post_issue_display(response_body['iid'])
165
+ response_body
166
+ end
84
167
 
168
+ # The method used to create branches
169
+ # @param name [String] the branch name
170
+ def create_branch(name)
171
+ check_status
172
+ git_remote = ask_for_remote
173
+ `git checkout #{CONFIG[:default_branch]}` # Be sure to be on the default branch.
174
+ from = `git branch | grep '*'`.gsub('* ', '').chomp
175
+ `git pull #{git_remote} HEAD` # Be sure to get the remote changes locally.
176
+ `git checkout -b #{name}` # Create the new branch.
177
+ to = `git branch | grep '*'`.gsub('* ', '').chomp
178
+ puts "\nYou are now working on branch #{to} created from #{from} !"
179
+ end
180
+
181
+ # The method used to get the issue description
182
+ # @return [String] the issue description
85
183
  def get_issue_description
86
184
  puts "\nWrite your issue description right bellow (save and quit with CTRL+D) :"
87
185
  puts "-----------------------------------------------------------------------\n\n"
88
186
  begin
89
187
  STDIN.read
90
- rescue Interrupt => int
188
+ rescue Interrupt
91
189
  puts %q"Why did you killed me ? :'("
92
190
  exit!
93
191
  end
94
192
  end
95
193
 
194
+ # The method used to get the issue title if not given the first time
195
+ # @return [String] the issue title
96
196
  def get_issue_title
97
- puts "\nWhat if your issue title :"
197
+ puts "\nWhat is your issue title :"
98
198
  puts "--------------------------\n\n"
99
199
  begin
100
200
  STDIN.gets.chomp
101
- rescue Interrupt => int
201
+ rescue Interrupt
102
202
  puts %q"Why did you killed me ? :'("
103
203
  exit!
104
204
  end
105
205
  end
106
206
 
107
- def post_issue_display(response)
108
- unless response['iid'].nil?
207
+ # The display method to let the user know
208
+ # if the issue has correctly been created
209
+ # @param issue_id [Integer] the id of the created issue
210
+ def post_issue_display(issue_id)
211
+ if !issue_id.nil?
109
212
  puts 'Your issue has been successfully created.'
110
213
  puts 'To view it, please follow the link bellow :'
111
- puts "\n#{CONFIG[:url]}/#{CONFIG[:project_slug]}/issues/#{response['iid']}"
214
+ puts "\n#{CONFIG[:url]}/#{CONFIG[:project_slug]}/issues/#{issue_id}"
112
215
  else
113
216
  puts %q(Your issue couldn't be created. Check your FGI configuration.)
114
217
  end
115
218
  end
116
219
 
117
- def post_estimation_display(response, estimation)
118
- if response['human_time_estimate'].nil?
220
+ # The display method to let the user know if the
221
+ # estimation time has correctly been set on the issue
222
+ # @param response_estimation [String] the estimation time response from the git service
223
+ # @param estimation [String] the estimation time given by the user
224
+ def post_estimation_display(response_estimation, estimation)
225
+ if response_estimation.nil?
119
226
  puts "\nWe weren't able to save your estimation."
120
227
  puts "You'll have to do it manually on #{CONFIG[:git_service].capitalize}."
121
228
  else
@@ -123,28 +230,59 @@ module Fgi
123
230
  end
124
231
  end
125
232
 
233
+ # The method used to commit the user's local changes
126
234
  def commit_changes
127
235
  puts 'Enter your commit message :'
128
236
  commit_message = STDIN.gets.chomp
129
- %x(git add .)
130
- %x(git commit -am '#{commit_message}')
237
+ `git add .`
238
+ `git commit -am '#{commit_message}'`
131
239
  puts 'Your changes have been commited !'
132
240
  end
133
241
 
242
+ # The method used to stash the user's local changes
134
243
  def stash_changes
135
- %x(git add .)
136
- %x(git stash)
244
+ `git add .`
245
+ `git stash`
137
246
  puts "\nYour changes have been stashed."
138
- puts "We will let you manually `git stash pop` to get your work back if needed.\n"
247
+ puts "We will let you manually git stash pop to get your work back if needed.\n"
248
+ end
249
+
250
+ # The method used to check if there are local changes and to
251
+ # ask the user if he want to commit or stash theses changes
252
+ def check_status
253
+ return if `git status -s`.empty?
254
+ begin
255
+ puts "\nThere are unsaved changes on your current branch."
256
+ puts 'Do you want to see them ? (y/n)'
257
+ puts '-------------------------------'
258
+ input = STDIN.gets.chomp
259
+ system('git diff') if %w[y yes].include?(input)
260
+
261
+ puts "\nDo you want to COMMIT theses changes ? (y/n)"
262
+ puts '--------------------------------------------'
263
+ input = STDIN.gets.chomp
264
+ if %w[y yes].include?(input)
265
+ commit_changes
266
+ else
267
+ stash_changes
268
+ end
269
+ rescue Interrupt
270
+ puts %q"Why did you killed me ? :'("
271
+ exit!
272
+ end
139
273
  end
140
274
 
141
- def snakecase(string)
142
- string.gsub(/::/, '/').
143
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
144
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
145
- tr('-', '_').
146
- tr(' ', '_').
147
- downcase
275
+ # The method used to snakify strings
276
+ # @param string [String] the string to snakify
277
+ # @return [String] the snakified string
278
+ def snakify(string)
279
+ string.gsub(/::/, '/')
280
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
281
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
282
+ .tr('-', '_')
283
+ .tr(' ', '_')
284
+ .tr("'", '_')
285
+ .downcase
148
286
  end
149
287
 
150
288
  end
@@ -3,27 +3,18 @@ module Fgi
3
3
  module GitServices
4
4
  class Gitlab
5
5
 
6
+ attr_reader :version, :token_header, :routes
7
+
6
8
  def initialize(config: CONFIG)
7
- @version = 'v4'
9
+ @version = 'v4'
10
+ @main_url = "#{config[:url]}/api/#{@version}"
8
11
  @token_header = 'PRIVATE-TOKEN'
9
12
  @routes = {
10
- projects: "#{config[:url]}/api/#{@version}/projects",
11
- search_projects: "#{config[:url]}/api/#{@version}/projects?search=",
12
- issues: "#{config[:url]}/api/#{@version}/projects/#{config[:project_id]}/issues",
13
- branches: "#{config[:url]}/api/#{@version}/projects/#{config[:project_id]}/repository/branches"
14
- }
15
- end
16
-
17
- def version
18
- @version
19
- end
20
-
21
- def token_header
22
- @token_header
23
- end
24
-
25
- def routes
26
- @routes
13
+ projects: "#{@main_url}/projects",
14
+ search_projects: "#{@main_url}/projects?search=",
15
+ issues: "#{@main_url}/projects/#{config[:project_id]}/issues",
16
+ branches: "#{@main_url}/projects/#{config[:project_id]}/repository/branches"
17
+ }
27
18
  end
28
19
 
29
20
  def to_sym
@@ -2,55 +2,56 @@
2
2
  module Fgi
3
3
  module HttpRequests
4
4
 
5
- # Generic method to GET requests
6
- # @param url [String] the given Git service API url for GET request
7
- # @param headers [Hash] the headers to set for the request
8
- # @return [String] the received response from the Git service API
9
- def get(url:, headers: nil)
10
- http_request(verb: :get, url: url, headers: headers)
5
+ # Generic method to GET requests
6
+ # @param url [String] the given Git service API url for GET request
7
+ # @param headers [Hash] the headers to set for the request
8
+ # @return [String] the received response from the Git service API
9
+ def get(url:, headers: nil)
10
+ http_request(verb: :get, url: url, headers: headers)
11
+ end
12
+
13
+ # Generic method to POST requests
14
+ # @param url [String] the given Git service API url for POST request
15
+ # @param headers [Hash] the headers to set for the request
16
+ # @param body [Hash] the body to set for the request
17
+ # @return [String] the received response from the Git service API
18
+ def post(url:, headers: nil, body: nil)
19
+ http_request(verb: :post, url: url, headers: headers, body: body)
20
+ end
21
+
22
+ private
23
+
24
+ # Generic method for HTTP requests
25
+ # @param url [String] the given Git service API url for a HTTP request
26
+ # @param headers [Hash] the headers to set for the request
27
+ # @param body [Hash] the body to set for the request
28
+ # @return [String] the received response from the Git service API
29
+ def http_request(verb:, url:, headers: nil, body: nil)
30
+ is_https = url.start_with?('https')
31
+ uri = URI.parse(url)
32
+
33
+ req = case verb
34
+ when :get
35
+ Net::HTTP::Get.new(url)
36
+ when :post
37
+ Net::HTTP::Post.new(url)
38
+ end
39
+
40
+ # Set headers if given
41
+ headers.each { |k, v| req[k] = v } unless headers.nil?
42
+ # Set body if given
43
+ req.body = body.to_json unless body.nil?
44
+
45
+ res = Net::HTTP.start(uri.host, uri.port, use_ssl: is_https) do |http|
46
+ http.request(req)
11
47
  end
12
48
 
13
- # Generic method to POST requests
14
- # @param url [String] the given Git service API url for POST request
15
- # @param headers [Hash] the headers to set for the request
16
- # @param body [Hash] the body to set for the request
17
- # @return [String] the received response from the Git service API
18
- def post(url:, headers: nil, body: nil)
19
- http_request(verb: :post, url: url, headers: headers)
20
- end
21
-
22
- private
23
-
24
- # Generic method for HTTP requests
25
- # @param url [String] the given Git service API url for a HTTP request
26
- # @param headers [Hash] the headers to set for the request
27
- # @param body [Hash] the body to set for the request
28
- # @return [String] the received response from the Git service API
29
- def http_request(verb:, url:, headers: nil, body: nil)
30
- is_https = url.start_with?('https')
31
- uri = URI.parse(url)
32
- req = case verb
33
- when :get
34
- Net::HTTP::Get.new(url)
35
- when :post
36
- Net::HTTP::Post.new(url)
37
- end
38
-
39
- # Set headers if given
40
- headers.each { |k, v| req[k] = v } unless headers.nil?
41
- # Set body if given
42
- req.body = body.to_json unless body.nil?
43
-
44
- res = Net::HTTP.start(uri.host, uri.port, use_ssl: is_https) do |http|
45
- http.request(req)
46
- end
47
-
48
- if res.code == '200'
49
- { status: '200', body: JSON.parse(res.body) }
50
- else
51
- { status: res.code, body: res.body }
52
- end
49
+ if res.code == '200'
50
+ { status: '200', body: JSON.parse(res.body) }
51
+ else
52
+ { status: res.code, body: res.body }
53
53
  end
54
+ end
54
55
 
55
56
  end
56
57
  end
data/lib/fgi/tokens.rb CHANGED
@@ -2,16 +2,21 @@
2
2
  module Fgi
3
3
  class Tokens
4
4
  class << self
5
+
5
6
  include HttpRequests
6
7
 
7
8
  # @param git_service_name [String] the git service to associate a token to
8
9
  # @param token [String] the token to associate to the git service
9
- def create_user_tokens_file(git_service, token)
10
- if File.exists?("#{Dir.home}/.tokens.fgi.yml")
10
+ def create_user_tokens_file(config:, git_service:, token:)
11
+ if File.exist?("#{Dir.home}/.tokens.fgi.yml")
11
12
  tokens = YAML.load_file("#{Dir.home}/.tokens.fgi.yml")
12
- tokens[git_service] = token
13
+ tokens[git_service.to_sym] = { config[:url] => token }
13
14
  else
14
- tokens = { git_service => token }
15
+ tokens = {
16
+ git_service => {
17
+ config[:url] => token
18
+ }
19
+ }
15
20
  end
16
21
  # Shouldn't we define some access restrictions on this file ?
17
22
  File.open("#{Dir.home}/.tokens.fgi.yml", 'w') { |f| f.write(tokens.to_yaml) }
@@ -34,12 +39,12 @@ module Fgi
34
39
  # @param git_service [Class] the current project's git service class
35
40
  # @return [String] the current token associated to the project's git service
36
41
  # @return [NilClass] if there is no token associated to the project's git service
37
- def get_token(git_service)
38
- if File.exists?("#{Dir.home}/.tokens.fgi.yml")
42
+ def get_token(config:, git_service:)
43
+ if File.exist?("#{Dir.home}/.tokens.fgi.yml")
39
44
  tokens = YAML.load_file("#{Dir.home}/.tokens.fgi.yml")
40
- tokens[git_service.to_sym]
45
+ tokens[git_service.to_sym][config[:url]]
41
46
  else
42
- puts "\nPlease enter your #{git_service.to_s} token :"
47
+ puts "\nPlease enter your #{git_service} token :"
43
48
  puts '(use `fgi --help` to check how to get your token)'
44
49
  puts '-------------------------------------------------'
45
50
  begin
@@ -47,7 +52,7 @@ module Fgi
47
52
  exit! if token == 'quit'
48
53
  return token if token_valid?(git_service, token)
49
54
  nil
50
- rescue Interrupt => int
55
+ rescue Interrupt
51
56
  exit!
52
57
  end
53
58
  end
@@ -57,7 +62,10 @@ module Fgi
57
62
  # @param token [String] the token to check the validity
58
63
  # @return [Boolean] true if the token is valid, false otherwise
59
64
  def token_valid?(git_service, token)
60
- response = get(url: git_service.routes[:projects], headers: { git_service.token_header => token })
65
+ response = get(
66
+ url: git_service.routes[:projects],
67
+ headers: { git_service.token_header => token }
68
+ )
61
69
  response[:status] == '200'
62
70
  end
63
71
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fgi
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julien Philibin
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-09-14 00:00:00.000000000 Z
12
+ date: 2017-10-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler