changelog_jira 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +233 -0
- data/Rakefile +39 -0
- data/bin/git-generate-changelog +4 -0
- data/bin/github_changelog_generator +4 -0
- data/lib/CHANGELOG.md +58 -0
- data/lib/github_changelog_generator.rb +41 -0
- data/lib/github_changelog_generator/fetcher.rb +221 -0
- data/lib/github_changelog_generator/generator/generator.rb +143 -0
- data/lib/github_changelog_generator/generator/generator_fetcher.rb +83 -0
- data/lib/github_changelog_generator/generator/generator_generation.rb +190 -0
- data/lib/github_changelog_generator/generator/generator_processor.rb +193 -0
- data/lib/github_changelog_generator/generator/generator_tags.rb +184 -0
- data/lib/github_changelog_generator/helper.rb +37 -0
- data/lib/github_changelog_generator/parser.rb +285 -0
- data/lib/github_changelog_generator/parser_file.rb +103 -0
- data/lib/github_changelog_generator/reader.rb +84 -0
- data/lib/github_changelog_generator/task.rb +67 -0
- data/lib/github_changelog_generator/version.rb +3 -0
- data/man/git-generate-changelog.1 +252 -0
- data/man/git-generate-changelog.html +262 -0
- data/man/git-generate-changelog.md +179 -0
- 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/install-gem-in-bundler.gemfile +3 -0
- data/spec/spec_helper.rb +55 -0
- data/spec/unit/fetcher_spec.rb +59 -0
- data/spec/unit/generator/generator_processor_spec.rb +28 -0
- data/spec/unit/generator/generator_tags_spec.rb +243 -0
- data/spec/unit/parse_file_spec.rb +73 -0
- data/spec/unit/parser_spec.rb +60 -0
- data/spec/unit/reader_spec.rb +113 -0
- metadata +190 -0
@@ -0,0 +1,184 @@
|
|
1
|
+
module GitHubChangelogGenerator
|
2
|
+
class Generator
|
3
|
+
# fetch, filter tags, fetch dates and sort them in time order
|
4
|
+
def fetch_and_filter_tags
|
5
|
+
@filtered_tags = get_filtered_tags(@fetcher.get_all_tags)
|
6
|
+
fetch_tags_dates
|
7
|
+
end
|
8
|
+
|
9
|
+
# Sort all tags by date
|
10
|
+
def sort_tags_by_date(tags)
|
11
|
+
puts "Sorting tags..." if @options[:verbose]
|
12
|
+
tags.sort_by! do |x|
|
13
|
+
get_time_of_tag(x)
|
14
|
+
end.reverse!
|
15
|
+
end
|
16
|
+
|
17
|
+
# Try to find tag date in local hash.
|
18
|
+
# Otherwise fFetch tag time and put it to local hash file.
|
19
|
+
# @param [Hash] tag_name name of the tag
|
20
|
+
# @return [Time] time of specified tag
|
21
|
+
def get_time_of_tag(tag_name)
|
22
|
+
raise ChangelogGeneratorError, "tag_name is nil".red if tag_name.nil?
|
23
|
+
|
24
|
+
name_of_tag = tag_name["name"]
|
25
|
+
time_for_name = @tag_times_hash[name_of_tag]
|
26
|
+
if !time_for_name.nil?
|
27
|
+
time_for_name
|
28
|
+
else
|
29
|
+
time_string = @fetcher.fetch_date_of_tag tag_name
|
30
|
+
@tag_times_hash[name_of_tag] = time_string
|
31
|
+
time_string
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Detect link, name and time for specified tag.
|
36
|
+
#
|
37
|
+
# @param [Hash] newer_tag newer tag. Can be nil, if it's Unreleased section.
|
38
|
+
# @return [Array] link, name and time of the tag
|
39
|
+
def detect_link_tag_time(newer_tag)
|
40
|
+
# if tag is nil - set current time
|
41
|
+
newer_tag_time = newer_tag.nil? ? Time.new : get_time_of_tag(newer_tag)
|
42
|
+
|
43
|
+
# if it's future release tag - set this value
|
44
|
+
if newer_tag.nil? && @options[:future_release]
|
45
|
+
newer_tag_name = @options[:future_release]
|
46
|
+
newer_tag_link = @options[:future_release]
|
47
|
+
else
|
48
|
+
# put unreleased label if there is no name for the tag
|
49
|
+
newer_tag_name = newer_tag.nil? ? @options[:unreleased_label] : newer_tag["name"]
|
50
|
+
newer_tag_link = newer_tag.nil? ? "HEAD" : newer_tag_name
|
51
|
+
end
|
52
|
+
[newer_tag_link, newer_tag_name, newer_tag_time]
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Object] try to find newest tag using #Reader and :base option if specified otherwise returns nil
|
56
|
+
def detect_since_tag
|
57
|
+
@since_tag ||= @options.fetch(:since_tag) { version_of_first_item }
|
58
|
+
end
|
59
|
+
|
60
|
+
def version_of_first_item
|
61
|
+
return unless File.file?(@options[:base].to_s)
|
62
|
+
|
63
|
+
sections = GitHubChangelogGenerator::Reader.new.read(@options[:base])
|
64
|
+
sections.first["version"] if sections && sections.any?
|
65
|
+
end
|
66
|
+
|
67
|
+
# Return tags after filtering tags in lists provided by option: --between-tags & --exclude-tags
|
68
|
+
#
|
69
|
+
# @return [Array]
|
70
|
+
def get_filtered_tags(all_tags)
|
71
|
+
filtered_tags = filter_since_tag(all_tags)
|
72
|
+
filtered_tags = filter_between_tags(filtered_tags)
|
73
|
+
filter_excluded_tags(filtered_tags)
|
74
|
+
end
|
75
|
+
|
76
|
+
# @param [Array] all_tags all tags
|
77
|
+
# @return [Array] filtered tags according :since_tag option
|
78
|
+
def filter_since_tag(all_tags)
|
79
|
+
filtered_tags = all_tags
|
80
|
+
tag = detect_since_tag
|
81
|
+
if tag
|
82
|
+
if all_tags.map(&:name).include? tag
|
83
|
+
idx = all_tags.index { |t| t.name == tag }
|
84
|
+
filtered_tags = if idx > 0
|
85
|
+
all_tags[0..idx - 1]
|
86
|
+
else
|
87
|
+
[]
|
88
|
+
end
|
89
|
+
else
|
90
|
+
Helper.log.warn "Warning: can't find tag #{tag}, specified with --since-tag option."
|
91
|
+
end
|
92
|
+
end
|
93
|
+
filtered_tags
|
94
|
+
end
|
95
|
+
|
96
|
+
# @param [Array] all_tags all tags
|
97
|
+
# @return [Array] filtered tags according :due_tag option
|
98
|
+
def filter_due_tag(all_tags)
|
99
|
+
filtered_tags = all_tags
|
100
|
+
tag = @options[:due_tag]
|
101
|
+
if tag
|
102
|
+
if (all_tags.count > 0) && (all_tags.map(&:name).include? tag)
|
103
|
+
idx = all_tags.index { |t| t.name == tag }
|
104
|
+
last_index = all_tags.count - 1
|
105
|
+
filtered_tags = if idx > 0 && idx < last_index
|
106
|
+
all_tags[idx + 1..last_index]
|
107
|
+
else
|
108
|
+
[]
|
109
|
+
end
|
110
|
+
else
|
111
|
+
Helper.log.warn "Warning: can't find tag #{tag}, specified with --due-tag option."
|
112
|
+
end
|
113
|
+
end
|
114
|
+
filtered_tags
|
115
|
+
end
|
116
|
+
|
117
|
+
# @param [Array] all_tags all tags
|
118
|
+
# @return [Array] filtered tags according :between_tags option
|
119
|
+
def filter_between_tags(all_tags)
|
120
|
+
filtered_tags = all_tags
|
121
|
+
if @options[:between_tags]
|
122
|
+
@options[:between_tags].each do |tag|
|
123
|
+
unless all_tags.map(&:name).include? tag
|
124
|
+
Helper.log.warn "Warning: can't find tag #{tag}, specified with --between-tags option."
|
125
|
+
end
|
126
|
+
end
|
127
|
+
filtered_tags = all_tags.select { |tag| @options[:between_tags].include? tag.name }
|
128
|
+
end
|
129
|
+
filtered_tags
|
130
|
+
end
|
131
|
+
|
132
|
+
# @param [Array] all_tags all tags
|
133
|
+
# @return [Array] filtered tags according :exclude_tags or :exclude_tags_regex option
|
134
|
+
def filter_excluded_tags(all_tags)
|
135
|
+
if @options[:exclude_tags]
|
136
|
+
apply_exclude_tags(all_tags)
|
137
|
+
elsif @options[:exclude_tags_regex]
|
138
|
+
apply_exclude_tags_regex(all_tags)
|
139
|
+
else
|
140
|
+
all_tags
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def apply_exclude_tags(all_tags)
|
147
|
+
if @options[:exclude_tags].is_a?(Regexp)
|
148
|
+
filter_tags_with_regex(all_tags, @options[:exclude_tags])
|
149
|
+
else
|
150
|
+
filter_exact_tags(all_tags)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def apply_exclude_tags_regex(all_tags)
|
155
|
+
filter_tags_with_regex(all_tags, Regexp.new(@options[:exclude_tags_regex]))
|
156
|
+
end
|
157
|
+
|
158
|
+
def filter_tags_with_regex(all_tags, regex)
|
159
|
+
warn_if_nonmatching_regex(all_tags)
|
160
|
+
all_tags.reject { |tag| regex =~ tag.name }
|
161
|
+
end
|
162
|
+
|
163
|
+
def filter_exact_tags(all_tags)
|
164
|
+
@options[:exclude_tags].each do |tag|
|
165
|
+
warn_if_tag_not_found(all_tags, tag)
|
166
|
+
end
|
167
|
+
all_tags.reject { |tag| @options[:exclude_tags].include? tag.name }
|
168
|
+
end
|
169
|
+
|
170
|
+
def warn_if_nonmatching_regex(all_tags)
|
171
|
+
unless all_tags.map(&:name).any? { |t| @options[:exclude_tags] =~ t }
|
172
|
+
Helper.log.warn "Warning: unable to reject any tag, using regex "\
|
173
|
+
"#{@options[:exclude_tags].inspect} in --exclude-tags "\
|
174
|
+
"option."
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def warn_if_tag_not_found(all_tags, tag)
|
179
|
+
unless all_tags.map(&:name).include? tag
|
180
|
+
Helper.log.warn "Warning: can't find tag #{tag}, specified with --exclude-tags option."
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "logger"
|
2
|
+
module GitHubChangelogGenerator
|
3
|
+
module Helper
|
4
|
+
# @return true if the currently running program is a unit test
|
5
|
+
def self.test?
|
6
|
+
defined? SpecHelper
|
7
|
+
end
|
8
|
+
|
9
|
+
@log ||= if test?
|
10
|
+
Logger.new(nil) # don't show any logs when running tests
|
11
|
+
else
|
12
|
+
Logger.new(STDOUT)
|
13
|
+
end
|
14
|
+
@log.formatter = proc do |severity, _datetime, _progname, msg|
|
15
|
+
string = "#{msg}\n"
|
16
|
+
|
17
|
+
if severity == "DEBUG"
|
18
|
+
string = string.magenta
|
19
|
+
elsif severity == "INFO"
|
20
|
+
string = string.white
|
21
|
+
elsif severity == "WARN"
|
22
|
+
string = string.yellow
|
23
|
+
elsif severity == "ERROR"
|
24
|
+
string = string.red
|
25
|
+
elsif severity == "FATAL"
|
26
|
+
string = string.red.bold
|
27
|
+
end
|
28
|
+
|
29
|
+
string
|
30
|
+
end
|
31
|
+
|
32
|
+
# Logging happens using this method
|
33
|
+
class << self
|
34
|
+
attr_reader :log
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,285 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "optparse"
|
3
|
+
require "pp"
|
4
|
+
require_relative "version"
|
5
|
+
require_relative "helper"
|
6
|
+
module GitHubChangelogGenerator
|
7
|
+
class Parser
|
8
|
+
# parse options with optparse
|
9
|
+
def self.parse_options
|
10
|
+
options = default_options
|
11
|
+
|
12
|
+
ParserFile.new(options).parse!
|
13
|
+
|
14
|
+
parser = setup_parser(options)
|
15
|
+
parser.parse!
|
16
|
+
|
17
|
+
user_and_project_from_git(options)
|
18
|
+
|
19
|
+
abort(parser.banner) unless options[:user] && options[:project]
|
20
|
+
|
21
|
+
print_options(options)
|
22
|
+
|
23
|
+
options
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param [Hash] options to display
|
27
|
+
def self.print_options(options)
|
28
|
+
if options[:verbose]
|
29
|
+
Helper.log.info "Performing task with options:"
|
30
|
+
options_to_display = options.clone
|
31
|
+
options_to_display[:token] = options_to_display[:token].nil? ? nil : "hidden value"
|
32
|
+
pp options_to_display
|
33
|
+
puts ""
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# setup parsing options
|
38
|
+
def self.setup_parser(options)
|
39
|
+
parser = OptionParser.new do |opts|
|
40
|
+
opts.banner = "Usage: github_changelog_generator [options]"
|
41
|
+
opts.on("-u", "--user [USER]", "Username of the owner of target GitHub repo") do |last|
|
42
|
+
options[:user] = last
|
43
|
+
end
|
44
|
+
opts.on("-p", "--project [PROJECT]", "Name of project on GitHub") do |last|
|
45
|
+
options[:project] = last
|
46
|
+
end
|
47
|
+
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|
|
48
|
+
options[:token] = last
|
49
|
+
end
|
50
|
+
opts.on("-f", "--date-format [FORMAT]", "Date format. Default is %Y-%m-%d") do |last|
|
51
|
+
options[:date_format] = last
|
52
|
+
end
|
53
|
+
opts.on("-o", "--output [NAME]", "Output file. Default is CHANGELOG.md") do |last|
|
54
|
+
options[:output] = last
|
55
|
+
end
|
56
|
+
opts.on("-b", "--base [NAME]", "Optional base file to append generated changes to.") do |last|
|
57
|
+
options[:base] = last
|
58
|
+
end
|
59
|
+
opts.on("--bugs-label [LABEL]", "Setup custom label for bug-fixes section. Default is \"**Fixed bugs:**""") do |v|
|
60
|
+
options[:bug_prefix] = v
|
61
|
+
end
|
62
|
+
opts.on("--enhancement-label [LABEL]", "Setup custom label for enhancements section. Default is \"**Implemented enhancements:**\"") do |v|
|
63
|
+
options[:enhancement_prefix] = v
|
64
|
+
end
|
65
|
+
opts.on("--issues-label [LABEL]", "Setup custom label for closed-issues section. Default is \"**Closed issues:**\"") do |v|
|
66
|
+
options[:issue_prefix] = v
|
67
|
+
end
|
68
|
+
opts.on("--header-label [LABEL]", "Setup custom header label. Default is \"# Change Log\"") do |v|
|
69
|
+
options[:header] = v
|
70
|
+
end
|
71
|
+
opts.on("--front-matter [JSON]", "Add YAML front matter. Formatted as JSON because it's easier to add on the command line") do |v|
|
72
|
+
options[:frontmatter] = JSON.parse(v).to_yaml + "---\n"
|
73
|
+
end
|
74
|
+
opts.on("--pr-label [LABEL]", "Setup custom label for pull requests section. Default is \"**Merged pull requests:**\"") do |v|
|
75
|
+
options[:merge_prefix] = v
|
76
|
+
end
|
77
|
+
opts.on("--[no-]issues", "Include closed issues in changelog. Default is true") do |v|
|
78
|
+
options[:issues] = v
|
79
|
+
end
|
80
|
+
opts.on("--[no-]issues-wo-labels", "Include closed issues without labels in changelog. Default is true") do |v|
|
81
|
+
options[:add_issues_wo_labels] = v
|
82
|
+
end
|
83
|
+
opts.on("--[no-]pr-wo-labels", "Include pull requests without labels in changelog. Default is true") do |v|
|
84
|
+
options[:add_pr_wo_labels] = v
|
85
|
+
end
|
86
|
+
opts.on("--[no-]pull-requests", "Include pull-requests in changelog. Default is true") do |v|
|
87
|
+
options[:pulls] = v
|
88
|
+
end
|
89
|
+
opts.on("--[no-]filter-by-milestone", "Use milestone to detect when issue was resolved. Default is true") do |last|
|
90
|
+
options[:filter_issues_by_milestone] = last
|
91
|
+
end
|
92
|
+
opts.on("--[no-]author", "Add author of pull-request in the end. Default is true") do |author|
|
93
|
+
options[:author] = author
|
94
|
+
end
|
95
|
+
opts.on("--unreleased-only", "Generate log from unreleased closed issues only.") do |v|
|
96
|
+
options[:unreleased_only] = v
|
97
|
+
end
|
98
|
+
opts.on("--[no-]unreleased", "Add to log unreleased closed issues. Default is true") do |v|
|
99
|
+
options[:unreleased] = v
|
100
|
+
end
|
101
|
+
opts.on("--unreleased-label [label]", "Add to log unreleased closed issues. Default is true") do |v|
|
102
|
+
options[:unreleased_label] = v
|
103
|
+
end
|
104
|
+
opts.on("--[no-]compare-link", "Include compare link (Full Changelog) between older version and newer version. Default is true") do |v|
|
105
|
+
options[:compare_link] = v
|
106
|
+
end
|
107
|
+
opts.on("--include-labels x,y,z", Array, "Only issues with the specified labels will be included in the changelog.") do |list|
|
108
|
+
options[:include_labels] = list
|
109
|
+
end
|
110
|
+
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|
|
111
|
+
options[:exclude_labels] = list
|
112
|
+
end
|
113
|
+
opts.on("--bug-labels x,y,z", Array, 'Issues with the specified labels will be always added to "Fixed bugs" section. Default is \'bug,Bug\'') do |list|
|
114
|
+
options[:bug_labels] = list
|
115
|
+
end
|
116
|
+
opts.on("--enhancement-labels x,y,z", Array, 'Issues with the specified labels will be always added to "Implemented enhancements" section. Default is \'enhancement,Enhancement\'') do |list|
|
117
|
+
options[:enhancement_labels] = list
|
118
|
+
end
|
119
|
+
opts.on("--between-tags x,y,z", Array, "Change log will be filled only between specified tags") do |list|
|
120
|
+
options[:between_tags] = list
|
121
|
+
end
|
122
|
+
opts.on("--exclude-tags x,y,z", Array, "Change log will exclude specified tags") do |list|
|
123
|
+
options[:exclude_tags] = list
|
124
|
+
end
|
125
|
+
opts.on("--exclude-tags-regex [REGEX]", "Apply a regular expression on tag names so that they can be excluded, for example: --exclude-tags-regex \".*\+\d{1,}\" ") do |last|
|
126
|
+
options[:exclude_tags_regex] = last
|
127
|
+
end
|
128
|
+
opts.on("--since-tag x", "Change log will start after specified tag") do |v|
|
129
|
+
options[:since_tag] = v
|
130
|
+
end
|
131
|
+
opts.on("--due-tag x", "Change log will end before specified tag") do |v|
|
132
|
+
options[:due_tag] = v
|
133
|
+
end
|
134
|
+
opts.on("--max-issues [NUMBER]", Integer, "Max number of issues to fetch from GitHub. Default is unlimited") do |max|
|
135
|
+
options[:max_issues] = max
|
136
|
+
end
|
137
|
+
opts.on("--release-url [URL]", "The URL to point to for release links, in printf format (with the tag as variable).") do |url|
|
138
|
+
options[:release_url] = url
|
139
|
+
end
|
140
|
+
opts.on("--github-site [URL]", "The Enterprise Github site on which your project is hosted.") do |last|
|
141
|
+
options[:github_site] = last
|
142
|
+
end
|
143
|
+
opts.on("--github-api [URL]", "The enterprise endpoint to use for your Github API.") do |last|
|
144
|
+
options[:github_endpoint] = last
|
145
|
+
end
|
146
|
+
opts.on("--simple-list", "Create simple list from issues and pull requests. Default is false.") do |v|
|
147
|
+
options[:simple_list] = v
|
148
|
+
end
|
149
|
+
opts.on("--future-release [RELEASE-VERSION]", "Put the unreleased changes in the specified release number.") do |future_release|
|
150
|
+
options[:future_release] = future_release
|
151
|
+
end
|
152
|
+
opts.on("--release-branch [RELEASE-BRANCH]", "Limit pull requests to the release branch, such as master or release") do |release_branch|
|
153
|
+
options[:release_branch] = release_branch
|
154
|
+
end
|
155
|
+
opts.on("--[no-]verbose", "Run verbosely. Default is true") do |v|
|
156
|
+
options[:verbose] = v
|
157
|
+
end
|
158
|
+
opts.on("-v", "--version", "Print version number") do |_v|
|
159
|
+
puts "Version: #{GitHubChangelogGenerator::VERSION}"
|
160
|
+
exit
|
161
|
+
end
|
162
|
+
opts.on("-h", "--help", "Displays Help") do
|
163
|
+
puts opts
|
164
|
+
exit
|
165
|
+
end
|
166
|
+
end
|
167
|
+
parser
|
168
|
+
end
|
169
|
+
|
170
|
+
# just get default options
|
171
|
+
def self.default_options
|
172
|
+
{
|
173
|
+
tag1: nil,
|
174
|
+
tag2: nil,
|
175
|
+
date_format: "%Y-%m-%d",
|
176
|
+
output: "CHANGELOG.md",
|
177
|
+
base: "HISTORY.md",
|
178
|
+
issues: true,
|
179
|
+
add_issues_wo_labels: true,
|
180
|
+
add_pr_wo_labels: true,
|
181
|
+
pulls: true,
|
182
|
+
filter_issues_by_milestone: true,
|
183
|
+
author: true,
|
184
|
+
unreleased: true,
|
185
|
+
unreleased_label: "Unreleased",
|
186
|
+
compare_link: true,
|
187
|
+
enhancement_labels: %w(enhancement Enhancement),
|
188
|
+
bug_labels: %w(bug Bug),
|
189
|
+
exclude_labels: %w(duplicate question invalid wontfix Duplicate Question Invalid Wontfix),
|
190
|
+
max_issues: nil,
|
191
|
+
simple_list: false,
|
192
|
+
verbose: true,
|
193
|
+
header: "# Change Log",
|
194
|
+
merge_prefix: "**Merged pull requests:**",
|
195
|
+
issue_prefix: "**Closed issues:**",
|
196
|
+
bug_prefix: "**Fixed bugs:**",
|
197
|
+
enhancement_prefix: "**Implemented enhancements:**",
|
198
|
+
git_remote: "origin"
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
def self.user_and_project_from_git(options)
|
203
|
+
if options[:user].nil? || options[:project].nil?
|
204
|
+
detect_user_and_project(options, ARGV[0], ARGV[1])
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Detects user and project from git
|
209
|
+
def self.detect_user_and_project(options, arg0 = nil, arg1 = nil)
|
210
|
+
options[:user], options[:project] = user_project_from_option(arg0, arg1, options[:github_site])
|
211
|
+
return if options[:user] && options[:project]
|
212
|
+
|
213
|
+
if ENV["RUBYLIB"] =~ /ruby-debug-ide/
|
214
|
+
options[:user] = "skywinder"
|
215
|
+
options[:project] = "changelog_test"
|
216
|
+
else
|
217
|
+
remote = `git config --get remote.#{options[:git_remote]}.url`
|
218
|
+
options[:user], options[:project] = user_project_from_remote(remote)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# Try to find user and project name from git remote output
|
223
|
+
#
|
224
|
+
# @param [String] output of git remote command
|
225
|
+
# @return [Array] user and project
|
226
|
+
def self.user_project_from_option(arg0, arg1, github_site)
|
227
|
+
user = nil
|
228
|
+
project = nil
|
229
|
+
github_site ||= "github.com"
|
230
|
+
if arg0 && !arg1
|
231
|
+
# this match should parse strings such "https://github.com/skywinder/Github-Changelog-Generator" or "skywinder/Github-Changelog-Generator" to user and name
|
232
|
+
puts arg0
|
233
|
+
match = /(?:.+#{Regexp.escape(github_site)}\/)?(.+)\/(.+)/.match(arg0)
|
234
|
+
|
235
|
+
begin
|
236
|
+
param = match[2].nil?
|
237
|
+
rescue
|
238
|
+
puts "Can't detect user and name from first parameter: '#{arg0}' -> exit'"
|
239
|
+
return
|
240
|
+
end
|
241
|
+
if param
|
242
|
+
return
|
243
|
+
else
|
244
|
+
user = match[1]
|
245
|
+
project = match[2]
|
246
|
+
end
|
247
|
+
end
|
248
|
+
[user, project]
|
249
|
+
end
|
250
|
+
|
251
|
+
# Try to find user and project name from git remote output
|
252
|
+
#
|
253
|
+
# @param [String] output of git remote command
|
254
|
+
# @return [Array] user and project
|
255
|
+
def self.user_project_from_remote(remote)
|
256
|
+
# try to find repo in format:
|
257
|
+
# origin git@github.com:skywinder/Github-Changelog-Generator.git (fetch)
|
258
|
+
# git@github.com:skywinder/Github-Changelog-Generator.git
|
259
|
+
regex1 = /.*(?:[:\/])((?:-|\w|\.)*)\/((?:-|\w|\.)*)(?:\.git).*/
|
260
|
+
|
261
|
+
# try to find repo in format:
|
262
|
+
# origin https://github.com/skywinder/ChangelogMerger (fetch)
|
263
|
+
# https://github.com/skywinder/ChangelogMerger
|
264
|
+
regex2 = /.*\/((?:-|\w|\.)*)\/((?:-|\w|\.)*).*/
|
265
|
+
|
266
|
+
remote_structures = [regex1, regex2]
|
267
|
+
|
268
|
+
user = nil
|
269
|
+
project = nil
|
270
|
+
remote_structures.each do |regex|
|
271
|
+
matches = Regexp.new(regex).match(remote)
|
272
|
+
|
273
|
+
if matches && matches[1] && matches[2]
|
274
|
+
puts "Detected user:#{matches[1]}, project:#{matches[2]}"
|
275
|
+
user = matches[1]
|
276
|
+
project = matches[2]
|
277
|
+
end
|
278
|
+
|
279
|
+
break unless matches.nil?
|
280
|
+
end
|
281
|
+
|
282
|
+
[user, project]
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|