fgi 0.2.6.3 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|