github_changelog_generator 1.3.11 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.hound.yml +2 -0
- data/.rspec +2 -0
- data/.rubocop.yml +8 -0
- data/.rubocop_todo.yml +81 -0
- data/.travis.yml +12 -10
- data/CHANGELOG.md +145 -113
- data/Gemfile +14 -4
- data/Gemfile.lock +75 -11
- data/README.md +17 -1
- data/Rakefile +5 -7
- data/bin/github_changelog_generator +2 -2
- data/bump_gemfile.rb +42 -48
- data/github_changelog_generator.gemspec +9 -10
- data/lib/CHANGELOG.md +2 -0
- data/lib/github_changelog_generator.rb +194 -346
- data/lib/github_changelog_generator/fetcher.rb +209 -0
- data/lib/github_changelog_generator/generator.rb +11 -8
- data/lib/github_changelog_generator/parser.rb +99 -86
- data/lib/github_changelog_generator/reader.rb +87 -0
- data/lib/github_changelog_generator/version.rb +1 -1
- data/spec/files/angular.js.md +9395 -0
- data/spec/files/bundler.md +1911 -0
- data/spec/files/github-changelog-generator.md +305 -0
- data/spec/spec_helper.rb +117 -0
- data/spec/unit/reader_spec.rb +113 -0
- metadata +22 -4
@@ -0,0 +1,209 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
3
|
+
module GitHubChangelogGenerator
|
4
|
+
# A Fetcher responsible for all requests to GitHub and all basic manipulation with related data
|
5
|
+
# (such as filtering, validating, e.t.c)
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
# fetcher = GitHubChangelogGenerator::Fetcher.new options
|
9
|
+
class Fetcher
|
10
|
+
PER_PAGE_NUMBER = 30
|
11
|
+
GH_RATE_LIMIT_EXCEEDED_MSG = "Warning: GitHub API rate limit (5000 per hour) exceeded, change log may be " \
|
12
|
+
"missing some issues. You can limit the number of issues fetched using the `--max-issues NUM` argument."
|
13
|
+
|
14
|
+
def initialize(options = {})
|
15
|
+
@options = options
|
16
|
+
|
17
|
+
@user = @options[:user]
|
18
|
+
@project = @options[:project]
|
19
|
+
@github_token = fetch_github_token
|
20
|
+
@tag_times_hash = {}
|
21
|
+
|
22
|
+
@logger = Logger.new(STDOUT)
|
23
|
+
@logger.formatter = proc do |_severity, _datetime, _progname, msg|
|
24
|
+
"#{msg}\n"
|
25
|
+
end
|
26
|
+
github_options = { per_page: PER_PAGE_NUMBER }
|
27
|
+
github_options[:oauth_token] = @github_token unless @github_token.nil?
|
28
|
+
github_options[:endpoint] = options[:github_endpoint] unless options[:github_endpoint].nil?
|
29
|
+
github_options[:site] = options[:github_endpoint] unless options[:github_site].nil?
|
30
|
+
|
31
|
+
begin
|
32
|
+
@github = Github.new github_options
|
33
|
+
rescue
|
34
|
+
@logger.warn GH_RATE_LIMIT_EXCEEDED_MSG.yellow
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns GitHub token. First try to use variable, provided by --token option,
|
39
|
+
# otherwise try to fetch it from CHANGELOG_GITHUB_TOKEN env variable.
|
40
|
+
#
|
41
|
+
# @return [String]
|
42
|
+
def fetch_github_token
|
43
|
+
env_var = @options[:token] ? @options[:token] : (ENV.fetch "CHANGELOG_GITHUB_TOKEN", nil)
|
44
|
+
|
45
|
+
unless env_var
|
46
|
+
@logger.warn "Warning: No token provided (-t option) and variable $CHANGELOG_GITHUB_TOKEN was not found.".yellow
|
47
|
+
@logger.warn "This script can make only 50 requests to GitHub API per hour without token!".yellow
|
48
|
+
end
|
49
|
+
|
50
|
+
env_var
|
51
|
+
end
|
52
|
+
|
53
|
+
# Fetch all tags from repo
|
54
|
+
# @return [Array] array of tags
|
55
|
+
def get_all_tags
|
56
|
+
if @options[:verbose]
|
57
|
+
print "Fetching tags...\r"
|
58
|
+
end
|
59
|
+
|
60
|
+
tags = []
|
61
|
+
|
62
|
+
begin
|
63
|
+
response = @github.repos.tags @options[:user], @options[:project]
|
64
|
+
page_i = 0
|
65
|
+
count_pages = response.count_pages
|
66
|
+
response.each_page do |page|
|
67
|
+
page_i += PER_PAGE_NUMBER
|
68
|
+
print "Fetching tags... #{page_i}/#{count_pages * PER_PAGE_NUMBER}\r"
|
69
|
+
tags.concat(page)
|
70
|
+
end
|
71
|
+
print " \r"
|
72
|
+
|
73
|
+
if tags.count == 0
|
74
|
+
@logger.warn "Warning: Can't find any tags in repo.\
|
75
|
+
Make sure, that you push tags to remote repo via 'git push --tags'".yellow
|
76
|
+
elsif @options[:verbose]
|
77
|
+
@logger.info "Found #{tags.count} tags"
|
78
|
+
end
|
79
|
+
|
80
|
+
rescue
|
81
|
+
@logger.warn GH_RATE_LIMIT_EXCEEDED_MSG.yellow
|
82
|
+
end
|
83
|
+
|
84
|
+
tags
|
85
|
+
end
|
86
|
+
|
87
|
+
# This method fetch all closed issues and separate them to pull requests and pure issues
|
88
|
+
# (pull request is kind of issue in term of GitHub)
|
89
|
+
# @return [Tuple] with issues and pull requests
|
90
|
+
def fetch_issues_and_pull_requests
|
91
|
+
if @options[:verbose]
|
92
|
+
print "Fetching closed issues...\r"
|
93
|
+
end
|
94
|
+
issues = []
|
95
|
+
|
96
|
+
begin
|
97
|
+
response = @github.issues.list user: @options[:user],
|
98
|
+
repo: @options[:project],
|
99
|
+
state: "closed",
|
100
|
+
filter: "all",
|
101
|
+
labels: nil
|
102
|
+
page_i = 0
|
103
|
+
count_pages = response.count_pages
|
104
|
+
response.each_page do |page|
|
105
|
+
page_i += PER_PAGE_NUMBER
|
106
|
+
print "Fetching issues... #{page_i}/#{count_pages * PER_PAGE_NUMBER}\r"
|
107
|
+
issues.concat(page)
|
108
|
+
break if @options[:max_issues] && issues.length >= @options[:max_issues]
|
109
|
+
end
|
110
|
+
rescue
|
111
|
+
@logger.warn GH_RATE_LIMIT_EXCEEDED_MSG.yellow
|
112
|
+
end
|
113
|
+
|
114
|
+
print " \r"
|
115
|
+
|
116
|
+
if @options[:verbose]
|
117
|
+
@logger.info "Received issues: #{issues.count}"
|
118
|
+
end
|
119
|
+
|
120
|
+
# remove pull request from issues:
|
121
|
+
issues.partition { |x|
|
122
|
+
x[:pull_request].nil?
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
# Fetch all pull requests. We need them to detect :merged_at parameter
|
127
|
+
# @return [Array] all pull requests
|
128
|
+
def fetch_pull_requests
|
129
|
+
pull_requests = []
|
130
|
+
begin
|
131
|
+
response = @github.pull_requests.list @options[:user], @options[:project], state: "closed"
|
132
|
+
page_i = 0
|
133
|
+
response.each_page do |page|
|
134
|
+
page_i += PER_PAGE_NUMBER
|
135
|
+
count_pages = response.count_pages
|
136
|
+
print "Fetching merged dates... #{page_i}/#{count_pages * PER_PAGE_NUMBER}\r"
|
137
|
+
pull_requests.concat(page)
|
138
|
+
end
|
139
|
+
rescue
|
140
|
+
@logger.warn GH_RATE_LIMIT_EXCEEDED_MSG.yellow
|
141
|
+
end
|
142
|
+
|
143
|
+
print " \r"
|
144
|
+
pull_requests
|
145
|
+
end
|
146
|
+
|
147
|
+
# Fetch event for all issues and add them to :events
|
148
|
+
# @param [Array] issues
|
149
|
+
# @return [Void]
|
150
|
+
def fetch_events_async(issues)
|
151
|
+
i = 0
|
152
|
+
max_thread_number = 50
|
153
|
+
threads = []
|
154
|
+
issues.each_slice(max_thread_number) { |issues_slice|
|
155
|
+
issues_slice.each { |issue|
|
156
|
+
threads << Thread.new {
|
157
|
+
begin
|
158
|
+
obj = @github.issues.events.list user: @options[:user],
|
159
|
+
repo: @options[:project],
|
160
|
+
issue_number: issue["number"]
|
161
|
+
rescue
|
162
|
+
@logger.warn GH_RATE_LIMIT_EXCEEDED_MSG.yellow
|
163
|
+
end
|
164
|
+
issue[:events] = obj.body
|
165
|
+
print "Fetching events for issues and PR: #{i + 1}/#{issues.count}\r"
|
166
|
+
i += 1
|
167
|
+
}
|
168
|
+
}
|
169
|
+
threads.each(&:join)
|
170
|
+
threads = []
|
171
|
+
}
|
172
|
+
|
173
|
+
# to clear line from prev print
|
174
|
+
print " \r"
|
175
|
+
|
176
|
+
if @options[:verbose]
|
177
|
+
@logger.info "Fetching events for issues and PR: #{i} Done!"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Try to find tag date in local hash.
|
182
|
+
# Otherwise fFetch tag time and put it to local hash file.
|
183
|
+
# @param [String] tag_name name of the tag
|
184
|
+
# @return [Time] time of specified tag
|
185
|
+
def get_time_of_tag(tag_name)
|
186
|
+
fail ChangelogGeneratorError, "tag_name is nil".red if tag_name.nil?
|
187
|
+
|
188
|
+
if @tag_times_hash[tag_name["name"]]
|
189
|
+
return @tag_times_hash[tag_name["name"]]
|
190
|
+
end
|
191
|
+
|
192
|
+
begin
|
193
|
+
github_git_data_commits_get = @github.git_data.commits.get @options[:user],
|
194
|
+
@options[:project],
|
195
|
+
tag_name["commit"]["sha"]
|
196
|
+
rescue
|
197
|
+
@logger.warn GH_RATE_LIMIT_EXCEEDED_MSG.yellow
|
198
|
+
end
|
199
|
+
time_string = github_git_data_commits_get["committer"]["date"]
|
200
|
+
@tag_times_hash[tag_name["name"]] = Time.parse(time_string)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Fetch commit for specifed event
|
204
|
+
# @return [Hash]
|
205
|
+
def fetch_commit(event)
|
206
|
+
@github.git_data.commits.get @options[:user], @options[:project], event[:commit_id]
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
@@ -1,12 +1,18 @@
|
|
1
1
|
module GitHubChangelogGenerator
|
2
2
|
class Generator
|
3
|
-
|
4
3
|
def initialize(options = nil)
|
5
4
|
@options = options
|
6
5
|
end
|
7
6
|
|
7
|
+
# Parse issue and generate single line formatted issue line.
|
8
|
+
#
|
9
|
+
# Example output:
|
10
|
+
# - Add coveralls integration [\#223](https://github.com/skywinder/github-changelog-generator/pull/223) ([skywinder](https://github.com/skywinder))
|
11
|
+
#
|
12
|
+
# @param [Hash] issue Fetched issue from GitHub
|
13
|
+
# @return [String] Markdown-formatted single issue
|
8
14
|
def get_string_for_issue(issue)
|
9
|
-
encapsulated_title =
|
15
|
+
encapsulated_title = encapsulate_string issue[:title]
|
10
16
|
|
11
17
|
title_with_number = "#{encapsulated_title} [\\##{issue[:number]}](#{issue.html_url})"
|
12
18
|
|
@@ -23,17 +29,14 @@ module GitHubChangelogGenerator
|
|
23
29
|
end
|
24
30
|
|
25
31
|
def encapsulate_string(string)
|
26
|
-
|
27
32
|
string.gsub! '\\', '\\\\'
|
28
33
|
|
29
34
|
encpas_chars = %w(> * _ \( \) [ ] #)
|
30
|
-
encpas_chars.each
|
35
|
+
encpas_chars.each do |char|
|
31
36
|
string.gsub! char, "\\#{char}"
|
32
|
-
|
37
|
+
end
|
33
38
|
|
34
39
|
string
|
35
40
|
end
|
36
|
-
|
37
41
|
end
|
38
|
-
|
39
|
-
end
|
42
|
+
end
|
@@ -1,114 +1,142 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require_relative
|
2
|
+
require "optparse"
|
3
|
+
require "pp"
|
4
|
+
require_relative "version"
|
5
5
|
|
6
6
|
module GitHubChangelogGenerator
|
7
7
|
class Parser
|
8
8
|
def self.parse_options
|
9
|
-
|
10
9
|
options = {
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
10
|
+
tag1: nil,
|
11
|
+
tag2: nil,
|
12
|
+
dateformat: "%Y-%m-%d",
|
13
|
+
output: "CHANGELOG.md",
|
14
|
+
issues: true,
|
15
|
+
add_issues_wo_labels: true,
|
16
|
+
add_pr_wo_labels: true,
|
17
|
+
pulls: true,
|
18
|
+
filter_issues_by_milestone: true,
|
19
|
+
author: true,
|
20
|
+
unreleased: true,
|
21
|
+
unreleased_label: "Unreleased",
|
22
|
+
compare_link: true,
|
23
|
+
include_labels: %w(bug enhancement),
|
24
|
+
exclude_labels: %w(duplicate question invalid wontfix),
|
25
|
+
max_issues: nil,
|
26
|
+
simple_list: false,
|
27
|
+
verbose: true,
|
28
|
+
|
29
|
+
merge_prefix: "**Merged pull requests:**",
|
30
|
+
issue_prefix: "**Closed issues:**",
|
31
|
+
bug_prefix: "**Fixed bugs:**",
|
32
|
+
enhancement_prefix: "**Implemented enhancements:**",
|
33
|
+
branch: "origin"
|
31
34
|
}
|
32
35
|
|
33
|
-
parser = OptionParser.new
|
34
|
-
opts.banner =
|
35
|
-
opts.on(
|
36
|
+
parser = OptionParser.new do |opts|
|
37
|
+
opts.banner = "Usage: github_changelog_generator [options]"
|
38
|
+
opts.on("-u", "--user [USER]", "Username of the owner of target GitHub repo") do |last|
|
36
39
|
options[:user] = last
|
37
40
|
end
|
38
|
-
opts.on(
|
41
|
+
opts.on("-p", "--project [PROJECT]", "Name of project on GitHub") do |last|
|
39
42
|
options[:project] = last
|
40
43
|
end
|
41
|
-
opts.on(
|
44
|
+
opts.on("-t", "--token [TOKEN]", "To make more than 50 requests per hour your GitHub token is required. You can generate it at: https://github.com/settings/tokens/new") do |last|
|
42
45
|
options[:token] = last
|
43
46
|
end
|
44
|
-
opts.on(
|
45
|
-
options[:
|
47
|
+
opts.on("-f", "--date-format [FORMAT]", "Date format. Default is %Y-%m-%d") do |last|
|
48
|
+
options[:dateformat] = last
|
46
49
|
end
|
47
|
-
opts.on(
|
50
|
+
opts.on("-o", "--output [NAME]", "Output file. Default is CHANGELOG.md") do |last|
|
48
51
|
options[:output] = last
|
49
52
|
end
|
50
|
-
opts.on(
|
53
|
+
opts.on("--[no-]issues", "Include closed issues in changelog. Default is true") do |v|
|
51
54
|
options[:issues] = v
|
52
55
|
end
|
53
|
-
opts.on(
|
56
|
+
opts.on("--[no-]issues-wo-labels", "Include closed issues without labels in changelog. Default is true") do |v|
|
54
57
|
options[:add_issues_wo_labels] = v
|
55
58
|
end
|
56
|
-
opts.on(
|
59
|
+
opts.on("--[no-]pr-wo-labels", "Include pull requests without labels in changelog. Default is true") do |v|
|
57
60
|
options[:add_pr_wo_labels] = v
|
58
61
|
end
|
59
|
-
opts.on(
|
62
|
+
opts.on("--[no-]pull-requests", "Include pull-requests in changelog. Default is true") do |v|
|
60
63
|
options[:pulls] = v
|
61
64
|
end
|
62
|
-
opts.on(
|
65
|
+
opts.on("--[no-]filter-by-milestone", "Use milestone to detect when issue was resolved. Default is true") do |last|
|
63
66
|
options[:filter_issues_by_milestone] = last
|
64
67
|
end
|
65
|
-
opts.on(
|
68
|
+
opts.on("--[no-]author", "Add author of pull-request in the end. Default is true") do |author|
|
66
69
|
options[:author] = author
|
67
70
|
end
|
68
|
-
opts.on(
|
71
|
+
opts.on("--unreleased-only", "Generate log from unreleased closed issues only.") do |v|
|
69
72
|
options[:unreleased_only] = v
|
70
73
|
end
|
71
|
-
opts.on(
|
74
|
+
opts.on("--[no-]unreleased", "Add to log unreleased closed issues. Default is true") do |v|
|
72
75
|
options[:unreleased] = v
|
73
76
|
end
|
74
|
-
opts.on(
|
77
|
+
opts.on("--unreleased-label [label]", "Add to log unreleased closed issues. Default is true") do |v|
|
75
78
|
options[:unreleased_label] = v
|
76
79
|
end
|
77
|
-
opts.on(
|
80
|
+
opts.on("--[no-]compare-link", "Include compare link (Full Changelog) between older version and newer version. Default is true") do |v|
|
78
81
|
options[:compare_link] = v
|
79
82
|
end
|
80
|
-
opts.on(
|
83
|
+
opts.on("--include-labels x,y,z", Array, 'Only issues with the specified labels will be included in the changelog. Default is \'bug,enhancement\'') do |list|
|
81
84
|
options[:include_labels] = list
|
82
85
|
end
|
83
|
-
opts.on(
|
86
|
+
opts.on("--exclude-labels x,y,z", Array, 'Issues with the specified labels will be always excluded from changelog. Default is \'duplicate,question,invalid,wontfix\'') do |list|
|
84
87
|
options[:exclude_labels] = list
|
85
88
|
end
|
86
|
-
opts.on(
|
89
|
+
opts.on("--max-issues [NUMBER]", Integer, "Max number of issues to fetch from GitHub. Default is unlimited") do |max|
|
90
|
+
options[:max_issues] = max
|
91
|
+
end
|
92
|
+
opts.on("--github-site [URL]", "The Enterprise Github site on which your project is hosted.") do |last|
|
87
93
|
options[:github_site] = last
|
88
94
|
end
|
89
|
-
opts.on(
|
95
|
+
opts.on("--github-api [URL]", "The enterprise endpoint to use for your Github API.") do |last|
|
90
96
|
options[:github_endpoint] = last
|
91
97
|
end
|
92
|
-
opts.on(
|
98
|
+
opts.on("--simple-list", "Create simple list from issues and pull requests. Default is false.") do |v|
|
93
99
|
options[:simple_list] = v
|
94
100
|
end
|
95
|
-
opts.on(
|
101
|
+
opts.on("--[no-]verbose", "Run verbosely. Default is true") do |v|
|
96
102
|
options[:verbose] = v
|
97
103
|
end
|
98
|
-
opts.on(
|
104
|
+
opts.on("-v", "--version", "Print version number") do |_v|
|
99
105
|
puts "Version: #{GitHubChangelogGenerator::VERSION}"
|
100
106
|
exit
|
101
107
|
end
|
102
|
-
opts.on(
|
108
|
+
opts.on("-h", "--help", "Displays Help") do
|
103
109
|
puts opts
|
104
110
|
exit
|
105
111
|
end
|
106
|
-
|
112
|
+
end
|
107
113
|
|
108
114
|
parser.parse!
|
109
115
|
|
116
|
+
detect_user_and_project(options)
|
117
|
+
|
118
|
+
if !options[:user] || !options[:project]
|
119
|
+
puts parser.banner
|
120
|
+
exit
|
121
|
+
end
|
122
|
+
|
123
|
+
if ARGV[1]
|
124
|
+
options[:tag1] = ARGV[0]
|
125
|
+
options[:tag2] = ARGV[1]
|
126
|
+
end
|
127
|
+
|
128
|
+
if options[:verbose]
|
129
|
+
puts "Performing task with options:"
|
130
|
+
pp options
|
131
|
+
puts ""
|
132
|
+
end
|
133
|
+
|
134
|
+
options
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.detect_user_and_project(options)
|
110
138
|
if ARGV[0] && !ARGV[1]
|
111
|
-
github_site = options[:github_site] ? options[:github_site] :
|
139
|
+
github_site = options[:github_site] ? options[:github_site] : "github.com"
|
112
140
|
# this match should parse strings such "https://github.com/skywinder/Github-Changelog-Generator" or "skywinder/Github-Changelog-Generator" to user and name
|
113
141
|
match = /(?:.+#{Regexp.escape(github_site)}\/)?(.+)\/(.+)/.match(ARGV[0])
|
114
142
|
|
@@ -122,52 +150,37 @@ module GitHubChangelogGenerator
|
|
122
150
|
exit
|
123
151
|
else
|
124
152
|
options[:user] = match[1]
|
125
|
-
options[:project]= match[2]
|
153
|
+
options[:project] = match[2]
|
126
154
|
end
|
127
155
|
|
128
|
-
|
129
156
|
end
|
130
157
|
|
131
158
|
if !options[:user] && !options[:project]
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
# git@github.com:skywinder/Github-Changelog-Generator.git
|
136
|
-
match = /.*(?:[:\/])((?:-|\w|\.)*)\/((?:-|\w|\.)*)(?:\.git).*/.match(remote)
|
137
|
-
|
138
|
-
if match && match[1] && match[2]
|
139
|
-
puts "Detected user:#{match[1]}, project:#{match[2]}"
|
140
|
-
options[:user], options[:project] = match[1], match[2]
|
159
|
+
if ENV["RUBYLIB"] =~ /ruby-debug-ide/
|
160
|
+
options[:user] = "skywinder"
|
161
|
+
options[:project] = "changelog_test"
|
141
162
|
else
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
163
|
+
remote = `git config --get remote.#{options[:branch]}.url`
|
164
|
+
# try to find repo in format:
|
165
|
+
# origin git@github.com:skywinder/Github-Changelog-Generator.git (fetch)
|
166
|
+
# git@github.com:skywinder/Github-Changelog-Generator.git
|
167
|
+
match = /.*(?:[:\/])((?:-|\w|\.)*)\/((?:-|\w|\.)*)(?:\.git).*/.match(remote)
|
168
|
+
|
146
169
|
if match && match[1] && match[2]
|
147
170
|
puts "Detected user:#{match[1]}, project:#{match[2]}"
|
148
171
|
options[:user], options[:project] = match[1], match[2]
|
172
|
+
else
|
173
|
+
# try to find repo in format:
|
174
|
+
# origin https://github.com/skywinder/ChangelogMerger (fetch)
|
175
|
+
# https://github.com/skywinder/ChangelogMerger
|
176
|
+
match = /.*\/((?:-|\w|\.)*)\/((?:-|\w|\.)*).*/.match(remote)
|
177
|
+
if match && match[1] && match[2]
|
178
|
+
puts "Detected user:#{match[1]}, project:#{match[2]}"
|
179
|
+
options[:user], options[:project] = match[1], match[2]
|
180
|
+
end
|
149
181
|
end
|
150
182
|
end
|
151
183
|
end
|
152
|
-
|
153
|
-
|
154
|
-
if !options[:user] || !options[:project]
|
155
|
-
puts parser.banner
|
156
|
-
exit
|
157
|
-
end
|
158
|
-
|
159
|
-
if ARGV[1]
|
160
|
-
options[:tag1] = ARGV[0]
|
161
|
-
options[:tag2] = ARGV[1]
|
162
|
-
end
|
163
|
-
|
164
|
-
if options[:verbose]
|
165
|
-
puts 'Performing task with options:'
|
166
|
-
pp options
|
167
|
-
puts ''
|
168
|
-
end
|
169
|
-
|
170
|
-
options
|
171
184
|
end
|
172
185
|
end
|
173
186
|
end
|