fgi 0.2.6.3 → 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 +4 -4
- data/bin/fgi +60 -0
- data/lib/fgi.rb +26 -13
- data/lib/fgi/configuration.rb +196 -0
- data/lib/fgi/git_service.rb +65 -0
- data/lib/fgi/git_services/gitlab.rb +38 -0
- data/lib/fgi/http_requests.rb +55 -0
- data/lib/fgi/tokens.rb +66 -0
- metadata +13 -22
- data/Gemfile +0 -4
- data/README.md +0 -35
- data/Rakefile +0 -6
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/exe/fgi +0 -44
- data/fgi.gemspec +0 -26
- data/lib/fgi/config.rb +0 -33
- data/lib/fgi/configurator.rb +0 -162
- data/lib/fgi/executor.rb +0 -11
- data/lib/fgi/generate_file.rb +0 -19
- data/lib/fgi/helper.rb +0 -28
- data/lib/fgi/html_request.rb +0 -36
- data/lib/fgi/version.rb +0 -3
- data/temp.txt +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02d08a9e357b68fd81e265725782dcc98328267a
|
4
|
+
data.tar.gz: 5c4fae2bb99e2871d2488898ea666cf0fff0d7d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e279751a9e0e1f5062a7ed1348bdef87c458a2d000ca0d0249db511abfdaf578a88d9d5790f48dbd6c98fe28aca6369205c366eac05f593dbf649f78340be990
|
7
|
+
data.tar.gz: 1ef9c20120cfe320029c7e7298f5763c6ca8b9393b7ca73fb0eef1886132d0b7053191e8c3ae8a620604a28ea7508a503d50ba9f66d21288c3ee3d1bd70610f4
|
data/bin/fgi
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# @author Matthieu Gourvénec <matthieu.gourvenec@gmail.com>
|
3
|
+
|
4
|
+
require_relative '../lib/fgi'
|
5
|
+
|
6
|
+
argv = ARGV
|
7
|
+
|
8
|
+
# ----------------------------- #
|
9
|
+
# FGI CMD DOC #
|
10
|
+
# ----------------------------- #
|
11
|
+
|
12
|
+
options = {}
|
13
|
+
options_parser = OptionParser.new do |fgi|
|
14
|
+
fgi.banner = 'Usage: fgi COMMAND [OPTION]'
|
15
|
+
fgi.separator ''
|
16
|
+
fgi.separator 'Commands'
|
17
|
+
fgi.separator ' config : run the fgi configurator.'
|
18
|
+
fgi.separator ' token [TOKEN] : define the new user token.'
|
19
|
+
fgi.separator ' new [ISSUE_NAME] : create the issue with the given name.'
|
20
|
+
fgi.separator ' ... more comming soon ...'
|
21
|
+
fgi.separator ''
|
22
|
+
fgi.separator 'Options'
|
23
|
+
|
24
|
+
fgi.on('-e', '--estimate ESTIMATION', 'How many time do you think you will spend on this issue ?') do |estimate|
|
25
|
+
options[:estimate] = estimate
|
26
|
+
end
|
27
|
+
|
28
|
+
fgi.on('-h', '--help', 'Display the FGI manual') do
|
29
|
+
puts options_parser
|
30
|
+
end
|
31
|
+
end
|
32
|
+
options_parser.parse!
|
33
|
+
|
34
|
+
# ---------------------------- #
|
35
|
+
# DISPATCHER #
|
36
|
+
# ---------------------------- #
|
37
|
+
|
38
|
+
def get_full_issue_title(argv)
|
39
|
+
return nil if argv[1].nil?
|
40
|
+
length = argv.length
|
41
|
+
argv[1..length].join(' ')
|
42
|
+
end
|
43
|
+
|
44
|
+
case argv[0]
|
45
|
+
when 'config'
|
46
|
+
Fgi::Configuration.new_config
|
47
|
+
when 'new'
|
48
|
+
Fgi.configured?
|
49
|
+
if argv[1].start_with?('-')
|
50
|
+
puts %q(You can't begin your issue's title with '-')
|
51
|
+
exit!
|
52
|
+
end
|
53
|
+
title = get_full_issue_title(argv)
|
54
|
+
Fgi::GitService.create_issue(title)
|
55
|
+
when 'token'
|
56
|
+
Fgi.configured?
|
57
|
+
Fgi::Tokens.add_token(argv[1])
|
58
|
+
else
|
59
|
+
puts options_parser
|
60
|
+
end
|
data/lib/fgi.rb
CHANGED
@@ -1,18 +1,31 @@
|
|
1
|
-
|
1
|
+
# @author Matthieu Gourvénec <matthieu.gourvenec@gmail.com>
|
2
|
+
module Fgi
|
2
3
|
|
3
|
-
require '
|
4
|
-
require '
|
4
|
+
require 'net/http'
|
5
|
+
require 'optparse'
|
6
|
+
require 'json'
|
7
|
+
require 'yaml'
|
8
|
+
require 'uri'
|
5
9
|
|
6
|
-
|
7
|
-
|
10
|
+
require_relative 'fgi/git_services/gitlab'
|
11
|
+
require_relative 'fgi/http_requests'
|
12
|
+
require_relative 'fgi/tokens'
|
13
|
+
require_relative 'fgi/configuration'
|
14
|
+
require_relative 'fgi/git_service'
|
15
|
+
|
16
|
+
# Define const variables if fgi config files exists
|
17
|
+
# otherwise ask for configuration
|
18
|
+
if File.exists?('.config.fgi.yml')
|
19
|
+
CONFIG = YAML.load_file('.config.fgi.yml')
|
20
|
+
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]
|
23
|
+
end
|
8
24
|
end
|
9
|
-
require_relative 'fgi/config'
|
10
|
-
require_relative 'fgi/version'
|
11
|
-
require_relative 'fgi/executor'
|
12
|
-
require_relative 'fgi/html_request'
|
13
|
-
require_relative 'fgi/helper'
|
14
|
-
require_relative 'fgi/configurator'
|
15
|
-
require_relative 'fgi/generate_file'
|
16
25
|
|
17
|
-
|
26
|
+
def self.configured?
|
27
|
+
return if File.exists?('.config.fgi.yml')
|
28
|
+
puts "\nThere is no FGI configuration file on this project. Please run 'fgi config'.\n\n"
|
29
|
+
exit!
|
30
|
+
end
|
18
31
|
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
# @author Matthieu Gourvénec <matthieu.gourvenec@gmail.com>
|
2
|
+
module Fgi
|
3
|
+
class Configuration
|
4
|
+
class << self
|
5
|
+
include HttpRequests
|
6
|
+
|
7
|
+
# Launch the process to create the fresh project fgi config file
|
8
|
+
def new_config
|
9
|
+
puts '####################################################################'
|
10
|
+
puts '## Welcome to Fast Gitlab Issues configuration ##'
|
11
|
+
puts "####################################################################\n\n"
|
12
|
+
|
13
|
+
# -------------------------- #
|
14
|
+
# CHECKERS #
|
15
|
+
# -------------------------- #
|
16
|
+
|
17
|
+
git_directory?
|
18
|
+
already_configured?
|
19
|
+
|
20
|
+
# -------------------------- #
|
21
|
+
# INITIALIZERS #
|
22
|
+
# -------------------------- #
|
23
|
+
|
24
|
+
|
25
|
+
# The hash that will contain the project's fgi configuration to save as yml
|
26
|
+
# It will contain :
|
27
|
+
# :url
|
28
|
+
# :routes
|
29
|
+
# :project_id
|
30
|
+
# :project_slug
|
31
|
+
config = {}
|
32
|
+
|
33
|
+
config[:git_service_class] = define_git_service
|
34
|
+
config[:url] = save_git_url
|
35
|
+
|
36
|
+
# Instanciation of the Git service class
|
37
|
+
git_service = config[:git_service_class].new(config: config)
|
38
|
+
config[:git_service] = git_service.to_sym
|
39
|
+
user_token = save_user_token(git_service)
|
40
|
+
project_name_and_id = define_project_name_and_id(git_service, user_token)
|
41
|
+
config = config.merge(project_name_and_id)
|
42
|
+
|
43
|
+
# -------------------------- #
|
44
|
+
# CREATORS #
|
45
|
+
# -------------------------- #
|
46
|
+
|
47
|
+
Fgi::Tokens.create_user_tokens_file(config[:git_service], user_token)
|
48
|
+
create_fgi_config_file(config)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# Check if we are in a git repository. Exit FGI if not.
|
54
|
+
def git_directory?
|
55
|
+
unless Dir.exists?('.git')
|
56
|
+
puts 'You are not in a git project repository.'
|
57
|
+
exit!
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Check if FGI has already been configured. Exit FGI if not.
|
62
|
+
def already_configured?
|
63
|
+
if File.exists?('.config.fgi.yml')
|
64
|
+
puts 'There is already a FGI config on this project.'
|
65
|
+
exit!
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Ask the user to shoose the project's Git service
|
70
|
+
# @return [Class] the project's Git service class
|
71
|
+
def define_git_service
|
72
|
+
puts "\nPlease insert the number of the used Git service :"
|
73
|
+
puts '--------------------------------------------------'
|
74
|
+
|
75
|
+
# Get the list of the Git service for which we provide FGI at the moment
|
76
|
+
git_services = Fgi::GitService.services
|
77
|
+
# Display theses services to let the user choose the project's one
|
78
|
+
git_services.each_with_index do |service, index|
|
79
|
+
puts "#{index+1} : #{service.capitalize}"
|
80
|
+
end
|
81
|
+
puts "... More soon ..."
|
82
|
+
|
83
|
+
begin
|
84
|
+
input = STDIN.gets.chomp
|
85
|
+
exit! if input == 'quit'
|
86
|
+
# Convert the string input to an integer
|
87
|
+
input = input.to_i
|
88
|
+
# If the input isn't out of range...
|
89
|
+
if (1..git_services.count).include?(input)
|
90
|
+
# Set a variable with the Git service name for displays
|
91
|
+
@git_service = git_services[input-1].capitalize
|
92
|
+
Fgi::GitServices.const_get(@git_service)
|
93
|
+
else
|
94
|
+
puts "\nSorry, the option is out of range. Try again :"
|
95
|
+
define_git_service
|
96
|
+
end
|
97
|
+
rescue Interrupt => int
|
98
|
+
exit!
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Ask for the Git service url.
|
103
|
+
# @return [String] the well formatted Git service URL
|
104
|
+
def save_git_url
|
105
|
+
puts "\nPlease enter your #{@git_service} url :"
|
106
|
+
puts 'example: http://gitlab.example.com/'
|
107
|
+
puts '-----------------------------------'
|
108
|
+
|
109
|
+
begin
|
110
|
+
input = STDIN.gets.chomp
|
111
|
+
exit! if input == 'quit'
|
112
|
+
# force scheme if not specified
|
113
|
+
input = "http://#{input}" if !input.start_with?('http://', 'https://')
|
114
|
+
# Call the entered url to know if it exist or not.
|
115
|
+
# If not, would raise an exception
|
116
|
+
get(url: input)
|
117
|
+
input
|
118
|
+
rescue Interrupt => int
|
119
|
+
exit!
|
120
|
+
rescue Exception => e
|
121
|
+
puts "\nOops, seems to be a bad url. Try again or quit (quit)"
|
122
|
+
save_git_url
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Ask for the user for his Git service token
|
127
|
+
# @param git_service [Class] the current project's git service class
|
128
|
+
# @return [String] the user Git service token
|
129
|
+
def save_user_token(git_service)
|
130
|
+
token = Fgi::Tokens.get_token(git_service)
|
131
|
+
return token unless token.nil?
|
132
|
+
save_user_token(git_service)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Ask the user to search for the project and to select the correct one.
|
136
|
+
# @param git_service [Class] the current project's git service class
|
137
|
+
# @param user_token [String] the user's token
|
138
|
+
# @return [Hash<String>] the hash which contain the project's slugname and id
|
139
|
+
def define_project_name_and_id(git_service, user_token)
|
140
|
+
puts "\nPlease enter the name of the current project :"
|
141
|
+
puts '----------------------------------------------'
|
142
|
+
|
143
|
+
begin
|
144
|
+
input = STDIN.gets.chomp
|
145
|
+
exit! if input == 'quit'
|
146
|
+
|
147
|
+
url = "#{git_service.routes[:search_projects]}#{input}"
|
148
|
+
response = get(url: url, headers: { git_service.token_header => user_token })
|
149
|
+
|
150
|
+
if response[:status] == '200' && !response[:body].empty?
|
151
|
+
puts "\nFound #{response[:body].count} match(es):"
|
152
|
+
response[:body].each_with_index do |project, index|
|
153
|
+
puts "#{index+1} - #{project['name_with_namespace']}"
|
154
|
+
end
|
155
|
+
|
156
|
+
validate_project_choice(response[:body])
|
157
|
+
|
158
|
+
else
|
159
|
+
puts "\nOops, we couldn't find a project called #{input}. Try again or quit (quit) :"
|
160
|
+
puts '-------------------------------------------------------------------'+('-'*input.length) # Don't be upset, i'm a perfectionist <3
|
161
|
+
define_project_name_and_id(git_service, user_token)
|
162
|
+
end
|
163
|
+
rescue Interrupt => int
|
164
|
+
exit!
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
def validate_project_choice(response_body)
|
170
|
+
puts "\nPlease insert the number of the current project :"
|
171
|
+
puts '---------------------------------------------------'
|
172
|
+
input = STDIN.gets.chomp
|
173
|
+
exit! if input == 'quit'
|
174
|
+
input = input.to_i
|
175
|
+
if (1..response_body.count).include?(input)
|
176
|
+
{
|
177
|
+
project_slug: response_body[input - 1]['path_with_namespace'],
|
178
|
+
project_id: response_body[input - 1]['id']
|
179
|
+
}
|
180
|
+
else
|
181
|
+
puts "\nSorry, the option is out of range. Try again :"
|
182
|
+
validate_project_choice(response_body)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def create_fgi_config_file(config)
|
187
|
+
File.open('.config.fgi.yml', 'w') { |f| f.write config.to_yaml }
|
188
|
+
|
189
|
+
puts "\nYou are now set to work on #{config[:project_slug]}."
|
190
|
+
puts 'Your configuration has been saved to .config.fgi.yml, enjoy !'
|
191
|
+
puts "\n#############################################################"
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# @author Matthieu Gourvénec <matthieu.gourvenec@gmail.com>
|
2
|
+
module Fgi
|
3
|
+
class GitService
|
4
|
+
class << self
|
5
|
+
include HttpRequests
|
6
|
+
|
7
|
+
def services
|
8
|
+
services = []
|
9
|
+
Dir.entries("#{File.dirname(__FILE__)}/git_services").each do |service|
|
10
|
+
services << service.gsub(/.rb/, '').to_sym unless %w(. ..).include?(service)
|
11
|
+
end
|
12
|
+
services
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_issue(title)
|
16
|
+
git_service = CONFIG[:git_service_class].new
|
17
|
+
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
|
+
|
25
|
+
post_issue_display(JSON.parse(response[:body]))
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def get_issue_description
|
31
|
+
puts "\nWrite your issue description right bellow (save and quit with CTRL+D) :"
|
32
|
+
puts "-----------------------------------------------------------------------\n\n"
|
33
|
+
begin
|
34
|
+
STDIN.read
|
35
|
+
rescue Interrupt => int
|
36
|
+
puts %q"Why did you killed me ? :'("
|
37
|
+
exit!
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_issue_title
|
42
|
+
puts "\nWhat if your issue title :"
|
43
|
+
puts "--------------------------\n\n"
|
44
|
+
begin
|
45
|
+
STDIN.gets.chomp
|
46
|
+
rescue Interrupt => int
|
47
|
+
puts %q"Why did you killed me ? :'("
|
48
|
+
exit!
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def post_issue_display(response)
|
53
|
+
if !response['iid'].nil?
|
54
|
+
puts 'Your issue has been successfully created.'
|
55
|
+
puts 'To view it, please follow the link bellow :'
|
56
|
+
puts "\n#{CONFIG[:url]}/#{CONFIG[:project_slug]}/issues/#{response['iid']}"
|
57
|
+
puts "\nThank you for using Fast Gitlab Issues!"
|
58
|
+
else
|
59
|
+
puts %q(Your issue couldn't be created. Check your FGI configuration.)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# @author Matthieu Gourvénec <matthieu.gourvenec@gmail.com>
|
2
|
+
module Fgi
|
3
|
+
module GitServices
|
4
|
+
class Gitlab
|
5
|
+
|
6
|
+
def initialize(config: CONFIG)
|
7
|
+
@version = 'v4'
|
8
|
+
@token_header = 'PRIVATE-TOKEN'
|
9
|
+
@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
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def version
|
17
|
+
@version
|
18
|
+
end
|
19
|
+
|
20
|
+
def token_header
|
21
|
+
@token_header
|
22
|
+
end
|
23
|
+
|
24
|
+
def routes
|
25
|
+
@routes
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_sym
|
29
|
+
:gitlab
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
'Gitlab'
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# @author Matthieu Gourvénec <matthieu.gourvenec@gmail.com>
|
2
|
+
module Fgi
|
3
|
+
module HttpRequests
|
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)
|
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)
|
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
|
+
uri = URI.parse(url)
|
31
|
+
req = case verb
|
32
|
+
when :get
|
33
|
+
Net::HTTP::Get.new(url)
|
34
|
+
when :post
|
35
|
+
Net::HTTP::Post.new(url)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Set headers if given
|
39
|
+
headers.each { |k, v| req[k] = v } unless headers.nil?
|
40
|
+
# Set body if given
|
41
|
+
req.body = body.to_json unless body.nil?
|
42
|
+
|
43
|
+
res = Net::HTTP.start(uri.host, uri.port) do |http|
|
44
|
+
http.request(req)
|
45
|
+
end
|
46
|
+
|
47
|
+
if res.code == '200'
|
48
|
+
{ status: '200', body: JSON.parse(res.body) }
|
49
|
+
else
|
50
|
+
{ status: res.code, body: res.body }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
data/lib/fgi/tokens.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# @author Matthieu Gourvénec <gourve_m@modulotech.fr>
|
2
|
+
module Fgi
|
3
|
+
class Tokens
|
4
|
+
class << self
|
5
|
+
include HttpRequests
|
6
|
+
|
7
|
+
# @param git_service_name [String] the git service to associate a token to
|
8
|
+
# @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")
|
11
|
+
tokens = YAML.load_file("#{Dir.home}/.tokens.fgi.yml")
|
12
|
+
tokens[git_service] = token
|
13
|
+
else
|
14
|
+
tokens = { git_service => token }
|
15
|
+
end
|
16
|
+
# Shouldn't we define some access restrictions on this file ?
|
17
|
+
File.open("#{Dir.home}/.tokens.fgi.yml", 'w') { |f| f.write(tokens.to_yaml) }
|
18
|
+
end
|
19
|
+
|
20
|
+
# Add a new token association for the user's fgi configuration
|
21
|
+
# @param token [String] the token to associate to the git service
|
22
|
+
def add_token(token)
|
23
|
+
git_service = CONFIG[:git_service_class].new
|
24
|
+
token = get_token(git_service) if token.nil?
|
25
|
+
if token_valid?(git_service, token)
|
26
|
+
create_user_tokens_file(CONFIG[:git_service], token)
|
27
|
+
puts "\nYour #{git_service} token has been successfully added !\n\n"
|
28
|
+
else
|
29
|
+
puts "\nOops, seems to be an invalid token. Try again.\n\n"
|
30
|
+
exit!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param git_service [Class] the current project's git service class
|
35
|
+
# @return [String] the current token associated to the project's git service
|
36
|
+
# @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")
|
39
|
+
tokens = YAML.load_file("#{Dir.home}/.tokens.fgi.yml")
|
40
|
+
tokens[git_service.to_sym]
|
41
|
+
else
|
42
|
+
puts "\nPlease enter your #{git_service.to_s} token :"
|
43
|
+
puts '(use `fgi --help` to check how to get your token)'
|
44
|
+
puts '-------------------------------------------------'
|
45
|
+
begin
|
46
|
+
token = STDIN.gets.chomp
|
47
|
+
exit! if token == 'quit'
|
48
|
+
return token if token_valid?(git_service, token)
|
49
|
+
nil
|
50
|
+
rescue Interrupt => int
|
51
|
+
exit!
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# @param git_service [Class] the current project's git service class
|
57
|
+
# @param token [String] the token to check the validity
|
58
|
+
# @return [Boolean] true if the token is valid, false otherwise
|
59
|
+
def token_valid?(git_service, token)
|
60
|
+
response = get(url: git_service.routes[:projects], headers: { git_service.token_header => token })
|
61
|
+
response[:status] == '200'
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
metadata
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fgi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0
|
4
|
+
version: '1.0'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julien Philibin
|
8
|
-
- Pedro Coutinho
|
9
8
|
- Matthieu Gourvénec
|
10
9
|
autorequire:
|
11
|
-
bindir:
|
10
|
+
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date: 2017-
|
12
|
+
date: 2017-08-17 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: bundler
|
@@ -54,30 +53,22 @@ dependencies:
|
|
54
53
|
- - "~>"
|
55
54
|
- !ruby/object:Gem::Version
|
56
55
|
version: '3.0'
|
57
|
-
description: Fast
|
56
|
+
description: Fast Git Issues.
|
58
57
|
email:
|
59
58
|
- philib_j@modulotech.fr
|
59
|
+
- gourve_m@modulotech.fr
|
60
60
|
executables:
|
61
61
|
- fgi
|
62
62
|
extensions: []
|
63
63
|
extra_rdoc_files: []
|
64
64
|
files:
|
65
|
-
-
|
66
|
-
- README.md
|
67
|
-
- Rakefile
|
68
|
-
- bin/console
|
69
|
-
- bin/setup
|
70
|
-
- exe/fgi
|
71
|
-
- fgi.gemspec
|
65
|
+
- bin/fgi
|
72
66
|
- lib/fgi.rb
|
73
|
-
- lib/fgi/
|
74
|
-
- lib/fgi/
|
75
|
-
- lib/fgi/
|
76
|
-
- lib/fgi/
|
77
|
-
- lib/fgi/
|
78
|
-
- lib/fgi/html_request.rb
|
79
|
-
- lib/fgi/version.rb
|
80
|
-
- temp.txt
|
67
|
+
- lib/fgi/configuration.rb
|
68
|
+
- lib/fgi/git_service.rb
|
69
|
+
- lib/fgi/git_services/gitlab.rb
|
70
|
+
- lib/fgi/http_requests.rb
|
71
|
+
- lib/fgi/tokens.rb
|
81
72
|
homepage: https://www.modulotech.fr
|
82
73
|
licenses: []
|
83
74
|
metadata: {}
|
@@ -97,8 +88,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
88
|
version: '0'
|
98
89
|
requirements: []
|
99
90
|
rubyforge_project:
|
100
|
-
rubygems_version: 2.
|
91
|
+
rubygems_version: 2.6.11
|
101
92
|
signing_key:
|
102
93
|
specification_version: 4
|
103
|
-
summary:
|
94
|
+
summary: Process and workflow simplifier for git projects.
|
104
95
|
test_files: []
|
data/Gemfile
DELETED
data/README.md
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
# Fgi
|
2
|
-
|
3
|
-
## Welcome to Fast Gitlab Issues!
|
4
|
-
|
5
|
-
Fast Gitlab Issues, aka Fgi, is a command line issue creation tool for Gitlab v8.8+.
|
6
|
-
|
7
|
-
To install, add the following to your project's Gemfile:
|
8
|
-
|
9
|
-
```ruby
|
10
|
-
gem 'fgi', git: 'https://github.com/moduloTech/fast-gitlab-issues.git'
|
11
|
-
```
|
12
|
-
|
13
|
-
And run `bundle install`.
|
14
|
-
|
15
|
-
After it finishes, run `$ fgi --config` if the gem is new to the project, or run `$ fgi --token <token>` if you are new to the project and fgi was previously installed.
|
16
|
-
|
17
|
-
You can create your token from Gitlab -> Settings -> Access Tokens
|
18
|
-
From then on, create your issues from the console:
|
19
|
-
|
20
|
-
```sh
|
21
|
-
$ fgi My awesome title goes here
|
22
|
-
```
|
23
|
-
|
24
|
-
This will open our default text editor (currently hardcoded to Vim) so you can provide a description, and when you close, it will create an issue on Gitlab. A link to the new issue will be provided if you want to check it out.
|
25
|
-
|
26
|
-
The following commands are currently supported:
|
27
|
-
|
28
|
-
$ fgi \<title\> \# initiates the process to create a gitlab issue
|
29
|
-
$ fgi --help \# opens this help menu
|
30
|
-
$ fgi --config \# starts the configuration wizard
|
31
|
-
$ fgi --token \<token\> \# saves the private gitlab token to a file and adds it to .gitignore
|
32
|
-
|
33
|
-
The config will ask you for your gitlab access token (you can get it from AF2) and the project URL from gitlab.
|
34
|
-
|
35
|
-
Any bugs/requests please open an issue, feel free to use fgi to do so!
|
data/Rakefile
DELETED
data/bin/console
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "fgi"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require "pry"
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require "irb"
|
14
|
-
IRB.start
|
data/bin/setup
DELETED
data/exe/fgi
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'open3'
|
4
|
-
require 'uri'
|
5
|
-
require 'net/http'
|
6
|
-
require_relative '../lib/fgi'
|
7
|
-
|
8
|
-
# extract core logic from here into the gem bin
|
9
|
-
module Fgi
|
10
|
-
class Command
|
11
|
-
def initialize(content)
|
12
|
-
# convert title into a string we can use in a curl request
|
13
|
-
content = content.join(' ')
|
14
|
-
case
|
15
|
-
when content.empty?
|
16
|
-
Fgi::Helper.run
|
17
|
-
when content.match(/--help/)
|
18
|
-
Fgi::Helper.run
|
19
|
-
when content.match(/--config/)
|
20
|
-
Fgi::Configurator.run
|
21
|
-
when content.match(/--token/)
|
22
|
-
Fgi::Configurator.validate_and_save_gitlab_token(content.strip.split(' ').last)
|
23
|
-
else
|
24
|
-
create_issue(content)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
# Get the issue's description and initiate its creation
|
29
|
-
# @param title [String] the issue's title
|
30
|
-
def create_issue(title)
|
31
|
-
puts "\nWrite your issue description right bellow (save and quit with CTRL+D) :"
|
32
|
-
puts "---------------------------------------------------------------------\n\n"
|
33
|
-
begin
|
34
|
-
description = STDIN.read
|
35
|
-
rescue Interrupt => int
|
36
|
-
puts %q[Why did you killed me ? :'(]
|
37
|
-
exit!
|
38
|
-
end
|
39
|
-
Fgi::Executor.new.process_data(title, description)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
Fgi::Command.new(ARGV)
|
data/fgi.gemspec
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'fgi/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = 'fgi'
|
8
|
-
spec.version = Fgi::VERSION
|
9
|
-
spec.authors = ['Julien Philibin', 'Pedro Coutinho', 'Matthieu Gourvénec']
|
10
|
-
spec.email = ['philib_j@modulotech.fr']
|
11
|
-
|
12
|
-
spec.summary = 'CLI for gitlab.'
|
13
|
-
spec.description = 'Fast Gitlab Issues.'
|
14
|
-
spec.homepage = 'https://www.modulotech.fr'
|
15
|
-
|
16
|
-
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
-
f.match(%r{^(test|spec|features)/})
|
18
|
-
end
|
19
|
-
spec.bindir = 'exe'
|
20
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
-
spec.require_paths = ['lib']
|
22
|
-
|
23
|
-
spec.add_development_dependency 'bundler', '~> 1.13'
|
24
|
-
spec.add_development_dependency 'rake', '~> 10.0'
|
25
|
-
spec.add_development_dependency 'rspec', '~> 3.0'
|
26
|
-
end
|
data/lib/fgi/config.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
module Fgi
|
2
|
-
class Config
|
3
|
-
class << self
|
4
|
-
def load(source)
|
5
|
-
@config = { :url => nil, :project_gitlab_id => nil, :project_namespaced => nil }
|
6
|
-
|
7
|
-
Fgi::GenerateFile.new(@config) if !File.exist?(source)
|
8
|
-
Fgi::GenerateFile.token if !File.exist?('.gitlab_access_token')
|
9
|
-
|
10
|
-
config = YAML.load_file(source)
|
11
|
-
token = File.open(".gitlab_access_token", "rb").read
|
12
|
-
@config.merge! config if config
|
13
|
-
@config[:token] = token
|
14
|
-
end
|
15
|
-
|
16
|
-
def include?(key)
|
17
|
-
@config.include?(key)
|
18
|
-
end
|
19
|
-
|
20
|
-
def [](key)
|
21
|
-
@config[key]
|
22
|
-
end
|
23
|
-
|
24
|
-
def to_yaml
|
25
|
-
@config.to_yaml
|
26
|
-
end
|
27
|
-
|
28
|
-
def current
|
29
|
-
@config ||= { :url => nil, :project_gitlab_id => nil, :project_namespaced => nil }
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
data/lib/fgi/configurator.rb
DELETED
@@ -1,162 +0,0 @@
|
|
1
|
-
module Fgi
|
2
|
-
class Configurator
|
3
|
-
class << self
|
4
|
-
|
5
|
-
def run
|
6
|
-
@config = Fgi::Config.current
|
7
|
-
is_git_dir?
|
8
|
-
puts '####################################################################'
|
9
|
-
puts ' Welcome to Fast Gitlab Issues configuration '
|
10
|
-
puts "####################################################################\n\n"
|
11
|
-
puts "#### Enter 'quit' or 'exit' at any time to go back to buisness! ####\n\n"
|
12
|
-
|
13
|
-
puts 'Please enter your Gitlab Url:'
|
14
|
-
validate_and_save_gitlab_uri
|
15
|
-
|
16
|
-
puts "\nPlease enter your Gitlab access token :"
|
17
|
-
puts "(You can generate new token from Gitlab -> Settings -> Access Tokens)"
|
18
|
-
puts '---------------------------------------'
|
19
|
-
validate_and_save_gitlab_token
|
20
|
-
|
21
|
-
puts "\nPlease enter the name of the current project :"
|
22
|
-
puts '----------------------------------------------'
|
23
|
-
search_and_save_project
|
24
|
-
|
25
|
-
File.open('.fast_gitlab_issues.yml', 'w') { |f| f.write @config.to_yaml }
|
26
|
-
puts "\nYou are now set to work on #{@config[:project_namespaced]}."
|
27
|
-
puts 'Your configuration has been saved to .fast_gitlab_issues.yml, enjoy !'
|
28
|
-
puts "\n####################################################################"
|
29
|
-
end
|
30
|
-
|
31
|
-
def validate_and_save_gitlab_token(inline_token = nil)
|
32
|
-
begin
|
33
|
-
@token = if inline_token.nil?
|
34
|
-
STDIN.gets.chomp
|
35
|
-
else
|
36
|
-
set_config
|
37
|
-
inline_token
|
38
|
-
end
|
39
|
-
if %w(quit exit).include?(@token)
|
40
|
-
puts 'See you back soon !'
|
41
|
-
exit!
|
42
|
-
end
|
43
|
-
rescue Interrupt => int
|
44
|
-
puts %q[Why did you killed me ? :'(]
|
45
|
-
exit!
|
46
|
-
end
|
47
|
-
@projects_uri = "#{@config[:url]}/api/v4/projects"
|
48
|
-
|
49
|
-
req = Net::HTTP::Get.new(@projects_uri)
|
50
|
-
req['PRIVATE-TOKEN'] = @token
|
51
|
-
res = Net::HTTP.start(@uri.hostname, @uri.port) { |http| http.request(req) }
|
52
|
-
|
53
|
-
if res.code == '200'
|
54
|
-
save_gitlab_token
|
55
|
-
else
|
56
|
-
puts "\nOops, seems to be an invalid token. Try again or quit (quit/exit) :"
|
57
|
-
puts '--------------------------------------------------------------'
|
58
|
-
validate_and_save_gitlab_token
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
|
64
|
-
def validate_and_save_gitlab_uri
|
65
|
-
puts 'example: http://gitlab.example.com/'
|
66
|
-
puts '-----------------------------------'
|
67
|
-
begin
|
68
|
-
input = STDIN.gets.chomp
|
69
|
-
if %w(quit exit).include?(input)
|
70
|
-
puts 'See you back soon !'
|
71
|
-
exit!
|
72
|
-
end
|
73
|
-
input = "http://#{input}" if !input.start_with?('http://', 'https://')
|
74
|
-
@uri = URI.parse("#{input}/")
|
75
|
-
@config[:url] = "#{@uri.scheme}://#{@uri.host}"
|
76
|
-
req = Net::HTTP.new(@uri.host, @uri.port)
|
77
|
-
res = req.request_head(@uri.path)
|
78
|
-
rescue Interrupt => int
|
79
|
-
puts %q[Why did you killed me ? :'(]
|
80
|
-
exit!
|
81
|
-
rescue Exception => e
|
82
|
-
puts "\nOops, seems to be a bad url. Try again or quit (quit/exit) :"
|
83
|
-
validate_and_save_gitlab_uri
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def save_gitlab_token
|
88
|
-
File.open('.gitlab_access_token', 'w') { |f| f.write @token }
|
89
|
-
if File.open('.gitignore').grep(/.gitlab_access_token/).empty?
|
90
|
-
open('.gitignore', 'a') do |f|
|
91
|
-
f.puts ''
|
92
|
-
f.puts '# Gfi secret token for gitlab'
|
93
|
-
f.puts '.gitlab_access_token'
|
94
|
-
end
|
95
|
-
end
|
96
|
-
puts "\nGitlab secret token successfully saved to file and added to .gitignore."
|
97
|
-
end
|
98
|
-
|
99
|
-
def search_and_save_project
|
100
|
-
begin
|
101
|
-
project_name = STDIN.gets.chomp
|
102
|
-
if %w(quit exit).include?(project_name)
|
103
|
-
puts 'See you back soon !'
|
104
|
-
exit!
|
105
|
-
end
|
106
|
-
rescue Interrupt => int
|
107
|
-
puts %q[Why did you killed me ? :'(]
|
108
|
-
exit!
|
109
|
-
end
|
110
|
-
|
111
|
-
req = Net::HTTP::Get.new("#{@projects_uri}?search=#{project_name}")
|
112
|
-
req['PRIVATE-TOKEN'] = @token
|
113
|
-
res = Net::HTTP.start(@uri.hostname, @uri.port) { |http| http.request(req) }
|
114
|
-
|
115
|
-
results = JSON.parse(res.body)
|
116
|
-
if res.code == '200' && !results.empty?
|
117
|
-
puts "\nFound #{results.count} match(es):"
|
118
|
-
results.each_with_index do |result, i|
|
119
|
-
puts "#{i+1} - #{result['name_with_namespace']}"
|
120
|
-
end
|
121
|
-
validate_option(results)
|
122
|
-
else
|
123
|
-
puts "\nOops, we couldn't find a project called #{project_name}. Try again or quit (quit/exit) :"
|
124
|
-
puts '-------------------------------------------------------------------'+('-'*project_name.length) # Yes, i'm a perfectionist <3
|
125
|
-
search_and_save_project
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
def validate_option(results)
|
130
|
-
puts "\nPlease insert the number of the current project :"
|
131
|
-
puts '-------------------------------------------------'
|
132
|
-
begin
|
133
|
-
option = STDIN.gets.chomp.to_i
|
134
|
-
rescue Interrupt => int
|
135
|
-
puts %q[Why did you killed me ? :'(]
|
136
|
-
exit!
|
137
|
-
end
|
138
|
-
if (1..results.length+1).include?(option)
|
139
|
-
@config[:project_gitlab_id] = results[option - 1]['id']
|
140
|
-
@config[:project_namespaced] = results[option - 1]['path_with_namespace']
|
141
|
-
else
|
142
|
-
puts "\nSorry, the option is out of range. Try again :"
|
143
|
-
validate_option(results)
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
def set_config
|
148
|
-
config_file = File.expand_path(CONFIG_FILE)
|
149
|
-
@config = YAML.load_file(config_file)
|
150
|
-
@uri = URI.parse(@config[:url])
|
151
|
-
end
|
152
|
-
|
153
|
-
def is_git_dir?
|
154
|
-
is_git_directory = Dir.exists?('.git')
|
155
|
-
if !is_git_directory
|
156
|
-
puts %q(This doesn't seem to be the root of a git repository, browse to the root of your project and try again.)
|
157
|
-
return
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
data/lib/fgi/executor.rb
DELETED
data/lib/fgi/generate_file.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
module Fgi
|
2
|
-
class GenerateFile
|
3
|
-
def initialize(config)
|
4
|
-
puts "Config file not found. Do you want to create a config file here? (Y/n)"
|
5
|
-
if STDIN.gets.chomp != 'Y'
|
6
|
-
puts "Closing...."
|
7
|
-
raise "Failed to find a configuration file."
|
8
|
-
else
|
9
|
-
Fgi::Configurator.run
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.token
|
14
|
-
puts 'Please provide a Gitlab access token before continuing:'
|
15
|
-
Fgi::Configurator.validate_and_save_gitlab_token
|
16
|
-
puts 'Thank you very much, we will now proceed.'
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/lib/fgi/helper.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
module Fgi
|
2
|
-
class Helper
|
3
|
-
class << self
|
4
|
-
def run
|
5
|
-
puts "
|
6
|
-
Welcome to Fast Gitlab Issues!
|
7
|
-
|
8
|
-
The following commands are currently supported:
|
9
|
-
|
10
|
-
fgi <title> # initiates the process to create a gitlab issue
|
11
|
-
fgi --help # opens this help menu
|
12
|
-
fgi --config # starts the configuration wizard
|
13
|
-
fgi --token <token> # saves the private gitlab token to a file and adds it to .gitignore
|
14
|
-
|
15
|
-
The config will ask you for your gitlab access token (you can get it from AF2) and the project URL from gitlab.
|
16
|
-
|
17
|
-
To create a gitlab issue just type:
|
18
|
-
|
19
|
-
$ fgi My awesome title goes here
|
20
|
-
|
21
|
-
Vim will open so you can write a description, and upon closing, it will be pushed to gitlab.
|
22
|
-
A success message should then appear.
|
23
|
-
|
24
|
-
"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
data/lib/fgi/html_request.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
module Fgi
|
2
|
-
class HTMLRequest
|
3
|
-
|
4
|
-
def initialize(title, description)
|
5
|
-
@title = title
|
6
|
-
@description = description
|
7
|
-
end
|
8
|
-
|
9
|
-
def push
|
10
|
-
uri = URI.parse(generate_link)
|
11
|
-
req = Net::HTTP::Post.new uri
|
12
|
-
req['PRIVATE-TOKEN'] = Fgi::Config[:token]
|
13
|
-
|
14
|
-
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
|
15
|
-
@response = JSON.parse(http.request(req).body)
|
16
|
-
end
|
17
|
-
|
18
|
-
if !@response['iid'].nil?
|
19
|
-
puts 'Your issue has been sucessfully created.'
|
20
|
-
puts 'To view it, please follow the link bellow:'
|
21
|
-
puts ''
|
22
|
-
puts "#{Fgi::Config[:url]}/#{Fgi::Config[:project_namespaced]}/issues/#{@response['iid'].to_s}"
|
23
|
-
puts ''
|
24
|
-
puts 'Thank you for using Fast Gitlab Issues!'
|
25
|
-
else
|
26
|
-
puts %q(I'm not really sure what happened, but I believe something went wrong.)
|
27
|
-
puts 'CALL HELP!!!'
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def generate_link
|
32
|
-
Fgi::Config[:url] + '/api/v4/projects/' + Fgi::Config[:project_gitlab_id].to_s + '/issues?title=' + URI.encode(@title) + '&description=' + URI.encode(@description)
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
36
|
-
end
|
data/lib/fgi/version.rb
DELETED
data/temp.txt
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
Some description.
|