gitlab-burndown 0.0.4
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/bin/gitlab-burndown +31 -0
- data/lib/gitlab-burndown/config/configuration.rb +25 -0
- data/lib/gitlab-burndown/config/env_file_configuration.rb +15 -0
- data/lib/gitlab-burndown/csv_field/category.rb +14 -0
- data/lib/gitlab-burndown/csv_field/closed_at.rb +11 -0
- data/lib/gitlab-burndown/csv_field/closed_state.rb +9 -0
- data/lib/gitlab-burndown/csv_field/field.rb +11 -0
- data/lib/gitlab-burndown/csv_field/fields.rb +15 -0
- data/lib/gitlab-burndown/csv_field/hour_estimate.rb +9 -0
- data/lib/gitlab-burndown/csv_field/iid.rb +7 -0
- data/lib/gitlab-burndown/csv_field/in_sprint.rb +10 -0
- data/lib/gitlab-burndown/csv_field/milestone.rb +9 -0
- data/lib/gitlab-burndown/csv_field/title.rb +7 -0
- data/lib/gitlab-burndown/csv_field/web_url.rb +7 -0
- data/lib/gitlab-burndown/error/illegal_access.rb +2 -0
- data/lib/gitlab-burndown/error/no_such_variable.rb +2 -0
- data/lib/gitlab-burndown/error/not_implemented.rb +2 -0
- data/lib/gitlab-burndown/fetcher/fetcher.rb +7 -0
- data/lib/gitlab-burndown/fetcher/group_issues.rb +16 -0
- data/lib/gitlab-burndown/filter/closed_after_date.rb +16 -0
- data/lib/gitlab-burndown/filter/filter.rb +7 -0
- data/lib/gitlab-burndown/filter/filter_list.rb +15 -0
- data/lib/gitlab-burndown/filter/no_include_labels.rb +14 -0
- data/lib/gitlab-burndown/generator/burndown_csv_generator.rb +16 -0
- data/lib/gitlab-burndown/generator/csv_generator.rb +21 -0
- data/lib/gitlab-burndown/generator/generator.rb +7 -0
- data/lib/gitlab-burndown/generator/issue_csv_generator.rb +40 -0
- data/lib/gitlab-burndown/gitlab/client.rb +23 -0
- data/lib/gitlab-burndown/net/http/client.rb +20 -0
- data/lib/gitlab-burndown/net/http/paginator.rb +22 -0
- data/lib/gitlab-burndown/net/http/response.rb +21 -0
- data/lib/gitlab-burndown/writer/file.rb +14 -0
- data/lib/gitlab-burndown/writer/string.rb +16 -0
- data/lib/gitlab-burndown/writer/writer.rb +7 -0
- metadata +77 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4e4d84f160a4747733a96bfb9bb2a6e1f0f23f60e4846106727af58c30d3e459
|
4
|
+
data.tar.gz: 70ac3b5102113d95cf768e026edc7c90ff92df64e104f55053cac78eea8a2141
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d8bc99707477f54b09a309945ed2ee4e7acd9a642c16043d55c5838bb6fe35e314eac410072e343c2b025423767e5758fe82d780f26d1a6c8bdb2acfa3b31506
|
7
|
+
data.tar.gz: '094f88b960120723f902db6fcc1b6c4e3ef656e9f1b0312818ae34cef533e0eb005ac7e9a09cc69a2d2e9b15a08b2262e8e181dbcd89be61ba2ca2c051b29c68'
|
data/bin/gitlab-burndown
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
require 'gitlab-burndown/config/env_file_configuration'
|
6
|
+
require 'gitlab-burndown/fetcher/group_issues'
|
7
|
+
require 'gitlab-burndown/filter/filter_list'
|
8
|
+
require 'gitlab-burndown/filter/closed_after_date'
|
9
|
+
require 'gitlab-burndown/filter/no_include_labels'
|
10
|
+
require 'gitlab-burndown/generator/burndown_csv_generator'
|
11
|
+
require 'gitlab-burndown/generator/issue_csv_generator'
|
12
|
+
require 'gitlab-burndown/gitlab/client'
|
13
|
+
require 'gitlab-burndown/writer/file'
|
14
|
+
|
15
|
+
if ARGV.length < 1
|
16
|
+
warn 'usage: gitlab-burndown <env_file>'
|
17
|
+
exit
|
18
|
+
end
|
19
|
+
|
20
|
+
environment_variables = %w[GL_TOKEN GL_HOST GL_API_VERSION GL_GROUP_ID INCLUDE_FROM_DATE EXCLUDE_LABELS OUTPUT_FILE]
|
21
|
+
config = EnvFileConfiguration.new(ARGV[0], environment_variables)
|
22
|
+
include_from_date = DateTime.iso8601(config.get('INCLUDE_FROM_DATE'))
|
23
|
+
labels_to_exclude = config.get('EXCLUDE_LABELS').split ','
|
24
|
+
|
25
|
+
client = GitlabHTTPClient.new(config)
|
26
|
+
issue_filter = FilterList.new(ClosedAfterDateFilter.new(include_from_date),
|
27
|
+
NoIncludeLabelsFilter.new(*labels_to_exclude))
|
28
|
+
issue_fetcher = GroupIssueFetcher.new(client, issue_filter, config.get('GL_GROUP_ID'))
|
29
|
+
csv_file_writer = FileWriter.new(config.get('OUTPUT_FILE'))
|
30
|
+
burndown_csv_generator = BurndownCSVGenerator.new(issue_fetcher, IssueCSVGenerator, csv_file_writer)
|
31
|
+
burndown_csv_generator.generate
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'gitlab-burndown/error/not_implemented'
|
2
|
+
require 'gitlab-burndown/error/no_such_variable'
|
3
|
+
|
4
|
+
class Configuration
|
5
|
+
def initialize(required_keys)
|
6
|
+
@required_keys = required_keys
|
7
|
+
@config = Hash.new
|
8
|
+
load!
|
9
|
+
ensure_required_keys_exist
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(variable_name)
|
13
|
+
@config[variable_name]
|
14
|
+
end
|
15
|
+
|
16
|
+
def load!
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
|
20
|
+
def ensure_required_keys_exist
|
21
|
+
@required_keys.each do |required_key|
|
22
|
+
raise NoSuchVariableError, required_key unless @config.key? required_key
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'gitlab-burndown/config/configuration'
|
2
|
+
|
3
|
+
class EnvFileConfiguration < Configuration
|
4
|
+
def initialize(filename, required_keys)
|
5
|
+
@filename = filename
|
6
|
+
super(required_keys)
|
7
|
+
end
|
8
|
+
|
9
|
+
def load!
|
10
|
+
File.foreach(@filename) do |line|
|
11
|
+
key_value_pair = line.split('=', 2)
|
12
|
+
@config[key_value_pair[0]] = key_value_pair[1].strip!
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'gitlab-burndown/csv_field/field'
|
2
|
+
|
3
|
+
class IssueCategoryCSVField < CSVField
|
4
|
+
def initialize(data_container)
|
5
|
+
super(data_container)
|
6
|
+
end
|
7
|
+
|
8
|
+
def format
|
9
|
+
category_label = @data_container['labels'].find { |label| label.include? 'Category::' }
|
10
|
+
return 'Uncategorized' if category_label.nil?
|
11
|
+
|
12
|
+
category_label.gsub('Category::', '')
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'gitlab-burndown/csv_field/field'
|
2
|
+
|
3
|
+
class CSVFields < CSVField
|
4
|
+
def initialize(data_container, *csv_field_constructors)
|
5
|
+
super(data_container)
|
6
|
+
@csv_field_constructors = csv_field_constructors
|
7
|
+
end
|
8
|
+
|
9
|
+
def format
|
10
|
+
formatted_fields = @csv_field_constructors.map do |constructor|
|
11
|
+
constructor.new(@data_container).format
|
12
|
+
end
|
13
|
+
"#{formatted_fields.join(';')}\n"
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'gitlab-burndown/fetcher/fetcher'
|
2
|
+
|
3
|
+
class GroupIssueFetcher < Fetcher
|
4
|
+
def initialize(gitlab_client, issue_filter, group_id)
|
5
|
+
super()
|
6
|
+
@gitlab_client = gitlab_client
|
7
|
+
@issue_filter = issue_filter
|
8
|
+
@group_id = group_id
|
9
|
+
end
|
10
|
+
|
11
|
+
def fetch
|
12
|
+
@gitlab_client.get_group_issues(@group_id).select do |issue|
|
13
|
+
@issue_filter.apply issue
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'gitlab-burndown/filter/filter'
|
3
|
+
|
4
|
+
class ClosedAfterDateFilter < Filter
|
5
|
+
def initialize(last_allowed_date)
|
6
|
+
super()
|
7
|
+
@last_allowed_date = last_allowed_date
|
8
|
+
end
|
9
|
+
|
10
|
+
def apply(target)
|
11
|
+
return true if @last_allowed_date.nil?
|
12
|
+
return true if target['closed_at'].nil?
|
13
|
+
|
14
|
+
Date.iso8601(target['closed_at']) > @last_allowed_date
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'gitlab-burndown/filter/filter'
|
2
|
+
|
3
|
+
class FilterList < Filter
|
4
|
+
def initialize(*filters)
|
5
|
+
super()
|
6
|
+
@filters = filters
|
7
|
+
end
|
8
|
+
|
9
|
+
def apply(target)
|
10
|
+
@filters.each do |filter|
|
11
|
+
return false unless filter.apply target
|
12
|
+
end
|
13
|
+
true
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'gitlab-burndown/filter/filter'
|
2
|
+
|
3
|
+
class NoIncludeLabelsFilter < Filter
|
4
|
+
def initialize(*labels)
|
5
|
+
super()
|
6
|
+
@labels = labels
|
7
|
+
end
|
8
|
+
|
9
|
+
def apply(target)
|
10
|
+
should_include = target['labels'].intersection(@labels).empty?
|
11
|
+
warn "Excluding '#{target['title']}' due to label filter" unless should_include
|
12
|
+
should_include
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'gitlab-burndown/generator/generator'
|
2
|
+
|
3
|
+
class BurndownCSVGenerator < Generator
|
4
|
+
def initialize(fetcher, csv_generator_constructor, writer)
|
5
|
+
super()
|
6
|
+
@fetcher = fetcher
|
7
|
+
@csv_generator_constructor = csv_generator_constructor
|
8
|
+
@writer = writer
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate
|
12
|
+
issues = @fetcher.fetch
|
13
|
+
csv = @csv_generator_constructor.new(issues).generate
|
14
|
+
@writer.write csv
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'gitlab-burndown/error/not_implemented'
|
2
|
+
require 'gitlab-burndown/generator/generator'
|
3
|
+
require 'gitlab-burndown/writer/string'
|
4
|
+
|
5
|
+
class CSVGenerator < Generator
|
6
|
+
def initialize(header)
|
7
|
+
super()
|
8
|
+
@header = header
|
9
|
+
@string_writer = StringWriter.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate
|
13
|
+
@string_writer.write "#{@header}\n"
|
14
|
+
write_csv_body
|
15
|
+
@string_writer.read
|
16
|
+
end
|
17
|
+
|
18
|
+
def write_csv_body
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'gitlab-burndown/generator/csv_generator'
|
2
|
+
require 'gitlab-burndown/csv_field/category'
|
3
|
+
require 'gitlab-burndown/csv_field/closed_at'
|
4
|
+
require 'gitlab-burndown/csv_field/closed_state'
|
5
|
+
require 'gitlab-burndown/csv_field/fields'
|
6
|
+
require 'gitlab-burndown/csv_field/hour_estimate'
|
7
|
+
require 'gitlab-burndown/csv_field/iid'
|
8
|
+
require 'gitlab-burndown/csv_field/in_sprint'
|
9
|
+
require 'gitlab-burndown/csv_field/milestone'
|
10
|
+
require 'gitlab-burndown/csv_field/title'
|
11
|
+
require 'gitlab-burndown/csv_field/web_url'
|
12
|
+
|
13
|
+
class IssueCSVGenerator < CSVGenerator
|
14
|
+
def initialize(issues)
|
15
|
+
super('IID;Title;Category;Milestone;Estimated hours;In current sprint;Is completed;Completed date;URL')
|
16
|
+
@issues = issues
|
17
|
+
end
|
18
|
+
|
19
|
+
def write_csv_body
|
20
|
+
@issues.each do |issue|
|
21
|
+
csv_line_builder = create_csv_line_builder_for_issue issue
|
22
|
+
@string_writer.write csv_line_builder.format
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_csv_line_builder_for_issue(issue)
|
27
|
+
CSVFields.new(
|
28
|
+
issue,
|
29
|
+
IssueIIDCSVField,
|
30
|
+
IssueTitleCSVField,
|
31
|
+
IssueCategoryCSVField,
|
32
|
+
IssueMilestoneCSVField,
|
33
|
+
IssueHourEstimateCSVField,
|
34
|
+
IssueInSprintCSVField,
|
35
|
+
IssueClosedStateCSVField,
|
36
|
+
IssueClosedAtCSVField,
|
37
|
+
IssueWebURLCSVField
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'gitlab-burndown/net/http/client'
|
2
|
+
require 'gitlab-burndown/net/http/paginator'
|
3
|
+
|
4
|
+
class GitlabHTTPClient < HTTPClient
|
5
|
+
def initialize(config)
|
6
|
+
token = config.get('GL_TOKEN')
|
7
|
+
host = config.get('GL_HOST')
|
8
|
+
api_version = config.get('GL_API_VERSION')
|
9
|
+
super(token)
|
10
|
+
@gitlab_api_host = "#{host}/api/#{api_version}"
|
11
|
+
@gitlab_group_id = config.get('GL_GROUP_ID')
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_group_issues(gitlab_group_id)
|
15
|
+
paginate_group_issues(gitlab_group_id, nil)
|
16
|
+
end
|
17
|
+
|
18
|
+
def paginate_group_issues(_gitlab_group_id, _pagination)
|
19
|
+
base_url = "#{@gitlab_api_host}/groups/#{@gitlab_group_id}/issues?per_page=100&page="
|
20
|
+
paginator = HTTPPaginator.new(self, base_url, 'x-total-pages')
|
21
|
+
paginator.paginate(nil)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'net/http'
|
3
|
+
require 'gitlab-burndown/net/http/response'
|
4
|
+
|
5
|
+
class HTTPClient
|
6
|
+
def initialize(auth_token)
|
7
|
+
@auth_token = auth_token
|
8
|
+
end
|
9
|
+
|
10
|
+
def get(url)
|
11
|
+
uri = URI(url)
|
12
|
+
request = Net::HTTP::Get.new(uri)
|
13
|
+
request['PRIVATE-TOKEN'] = @auth_token
|
14
|
+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http_context|
|
15
|
+
http_context.request(request)
|
16
|
+
end
|
17
|
+
|
18
|
+
HTTPResponse.new(response)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Pagination = Struct.new(:page, :results)
|
2
|
+
|
3
|
+
class HTTPPaginator
|
4
|
+
def initialize(client, base_url, header_total_pages)
|
5
|
+
@client = client
|
6
|
+
@base_url = base_url
|
7
|
+
@header_total_pages = header_total_pages
|
8
|
+
end
|
9
|
+
|
10
|
+
def paginate(pagination)
|
11
|
+
pagination = Pagination.new(1, []) if pagination.nil?
|
12
|
+
url = "#{@base_url}#{pagination.page}"
|
13
|
+
warn "Reading #{url}"
|
14
|
+
response = @client.get(url)
|
15
|
+
pagination.results.concat(response.json)
|
16
|
+
|
17
|
+
return pagination.results if response.header(@header_total_pages) == pagination.page.to_s
|
18
|
+
|
19
|
+
pagination.page += 1
|
20
|
+
paginate(pagination)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class HTTPResponse
|
2
|
+
def initialize(builtin_response)
|
3
|
+
@builtin_response = builtin_response
|
4
|
+
end
|
5
|
+
|
6
|
+
def body
|
7
|
+
@builtin_response.body
|
8
|
+
end
|
9
|
+
|
10
|
+
def text
|
11
|
+
body
|
12
|
+
end
|
13
|
+
|
14
|
+
def json
|
15
|
+
JSON.parse(body)
|
16
|
+
end
|
17
|
+
|
18
|
+
def header(header_name)
|
19
|
+
@builtin_response[header_name]
|
20
|
+
end
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gitlab-burndown
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andreas Kruhlmann
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-02-09 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: ''
|
14
|
+
email: andreas.kruehlmann@siemens.com
|
15
|
+
executables:
|
16
|
+
- gitlab-burndown
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- bin/gitlab-burndown
|
21
|
+
- lib/gitlab-burndown/config/configuration.rb
|
22
|
+
- lib/gitlab-burndown/config/env_file_configuration.rb
|
23
|
+
- lib/gitlab-burndown/csv_field/category.rb
|
24
|
+
- lib/gitlab-burndown/csv_field/closed_at.rb
|
25
|
+
- lib/gitlab-burndown/csv_field/closed_state.rb
|
26
|
+
- lib/gitlab-burndown/csv_field/field.rb
|
27
|
+
- lib/gitlab-burndown/csv_field/fields.rb
|
28
|
+
- lib/gitlab-burndown/csv_field/hour_estimate.rb
|
29
|
+
- lib/gitlab-burndown/csv_field/iid.rb
|
30
|
+
- lib/gitlab-burndown/csv_field/in_sprint.rb
|
31
|
+
- lib/gitlab-burndown/csv_field/milestone.rb
|
32
|
+
- lib/gitlab-burndown/csv_field/title.rb
|
33
|
+
- lib/gitlab-burndown/csv_field/web_url.rb
|
34
|
+
- lib/gitlab-burndown/error/illegal_access.rb
|
35
|
+
- lib/gitlab-burndown/error/no_such_variable.rb
|
36
|
+
- lib/gitlab-burndown/error/not_implemented.rb
|
37
|
+
- lib/gitlab-burndown/fetcher/fetcher.rb
|
38
|
+
- lib/gitlab-burndown/fetcher/group_issues.rb
|
39
|
+
- lib/gitlab-burndown/filter/closed_after_date.rb
|
40
|
+
- lib/gitlab-burndown/filter/filter.rb
|
41
|
+
- lib/gitlab-burndown/filter/filter_list.rb
|
42
|
+
- lib/gitlab-burndown/filter/no_include_labels.rb
|
43
|
+
- lib/gitlab-burndown/generator/burndown_csv_generator.rb
|
44
|
+
- lib/gitlab-burndown/generator/csv_generator.rb
|
45
|
+
- lib/gitlab-burndown/generator/generator.rb
|
46
|
+
- lib/gitlab-burndown/generator/issue_csv_generator.rb
|
47
|
+
- lib/gitlab-burndown/gitlab/client.rb
|
48
|
+
- lib/gitlab-burndown/net/http/client.rb
|
49
|
+
- lib/gitlab-burndown/net/http/paginator.rb
|
50
|
+
- lib/gitlab-burndown/net/http/response.rb
|
51
|
+
- lib/gitlab-burndown/writer/file.rb
|
52
|
+
- lib/gitlab-burndown/writer/string.rb
|
53
|
+
- lib/gitlab-burndown/writer/writer.rb
|
54
|
+
homepage: https://mo-gitlab.siemens.dk/sw-group/foundation/gitlab-burndown-csv-generator
|
55
|
+
licenses:
|
56
|
+
- Nonstandard
|
57
|
+
metadata: {}
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubygems_version: 3.3.15
|
74
|
+
signing_key:
|
75
|
+
specification_version: 4
|
76
|
+
summary: GitLab burndown chart generator
|
77
|
+
test_files: []
|