reports_kits 0.7.5 → 0.7.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +6 -0
- data/.rubocop.yml +85 -0
- data/.travis.yml +21 -0
- data/Appraisals +27 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.md +35 -0
- data/Rakefile +2 -0
- data/app/assets/javascripts/reports_kits/application.js +14 -0
- data/app/assets/javascripts/reports_kits/lib/_init.js +9 -0
- data/app/assets/javascripts/reports_kits/lib/chart.js +73 -0
- data/app/assets/javascripts/reports_kits/lib/report.js +135 -0
- data/app/assets/javascripts/reports_kits/lib/table.js +87 -0
- data/app/assets/javascripts/reports_kits/vendor/chart.js +12269 -0
- data/app/assets/javascripts/reports_kits/vendor/daterangepicker.js +1627 -0
- data/app/assets/javascripts/reports_kits/vendor/jquery.tablesorter.min.js +4 -0
- data/app/assets/javascripts/reports_kits/vendor/moment.js +4040 -0
- data/app/assets/javascripts/reports_kits/vendor/select2.full.js +6436 -0
- data/app/assets/stylesheets/reports_kits/application.css.scss +3 -0
- data/app/assets/stylesheets/reports_kits/reports.css.sass +33 -0
- data/app/assets/stylesheets/reports_kits/select2_overrides.css.sass +7 -0
- data/app/assets/stylesheets/reports_kits/vendor/daterangepicker.css +269 -0
- data/app/assets/stylesheets/reports_kits/vendor/select2-bootstrap.css +721 -0
- data/app/assets/stylesheets/reports_kits/vendor/select2.css +484 -0
- data/config/initializers/mime_types.rb +1 -0
- data/config/routes.rb +10 -0
- data/docs/images/demo.gif +0 -0
- data/docs/images/users_by_created_at.png +0 -0
- data/gemfiles/mysql.gemfile +7 -0
- data/gemfiles/mysql.gemfile.lock +167 -0
- data/gemfiles/postgresql.gemfile +7 -0
- data/gemfiles/postgresql.gemfile.lock +165 -0
- data/gemfiles/postgresql_rails_5.1.4.gemfile +8 -0
- data/gemfiles/postgresql_rails_5.1.4.gemfile.lock +168 -0
- data/gemfiles/rails_4_mysql.gemfile +8 -0
- data/gemfiles/rails_4_mysql.gemfile.lock +165 -0
- data/gemfiles/rails_4_postgresql.gemfile +8 -0
- data/gemfiles/rails_4_postgresql.gemfile.lock +163 -0
- data/gemfiles/rails_5.1.4_postgresql.gemfile +8 -0
- data/gemfiles/rails_5.1.4_postgresql.gemfile.lock +169 -0
- data/gemfiles/rails_5_mysql.gemfile +8 -0
- data/gemfiles/rails_5_mysql.gemfile.lock +171 -0
- data/gemfiles/rails_5_postgresql.gemfile +8 -0
- data/gemfiles/rails_5_postgresql.gemfile.lock +169 -0
- data/lib/reports_kits/base_controller.rb +17 -0
- data/lib/reports_kits/cache.rb +37 -0
- data/lib/reports_kits/configuration.rb +50 -0
- data/lib/reports_kits/engine.rb +21 -0
- data/lib/reports_kits/entity.rb +3 -0
- data/lib/reports_kits/filters_controller.rb +11 -0
- data/lib/reports_kits/form_builder.rb +66 -0
- data/lib/reports_kits/helper.rb +24 -0
- data/lib/reports_kits/model.rb +16 -0
- data/lib/reports_kits/model_configuration.rb +28 -0
- data/lib/reports_kits/normalized_params.rb +16 -0
- data/lib/reports_kits/order.rb +33 -0
- data/lib/reports_kits/relative_time.rb +42 -0
- data/lib/reports_kits/report_builder.rb +88 -0
- data/lib/reports_kits/reports/abstract_series.rb +9 -0
- data/lib/reports_kits/reports/adapters/mysql.rb +26 -0
- data/lib/reports_kits/reports/adapters/postgresql.rb +26 -0
- data/lib/reports_kits/reports/composite_series.rb +48 -0
- data/lib/reports_kits/reports/contextual_filter.rb +19 -0
- data/lib/reports_kits/reports/data/add_table_aggregations.rb +105 -0
- data/lib/reports_kits/reports/data/aggregate_composite.rb +97 -0
- data/lib/reports_kits/reports/data/aggregate_one_dimension.rb +39 -0
- data/lib/reports_kits/reports/data/aggregate_two_dimensions.rb +39 -0
- data/lib/reports_kits/reports/data/chart_data_for_data_method.rb +62 -0
- data/lib/reports_kits/reports/data/chart_options.rb +155 -0
- data/lib/reports_kits/reports/data/format_one_dimension.rb +140 -0
- data/lib/reports_kits/reports/data/format_table.rb +63 -0
- data/lib/reports_kits/reports/data/format_two_dimensions.rb +143 -0
- data/lib/reports_kits/reports/data/generate.rb +156 -0
- data/lib/reports_kits/reports/data/generate_for_properties.rb +97 -0
- data/lib/reports_kits/reports/data/normalize_properties.rb +62 -0
- data/lib/reports_kits/reports/data/populate_one_dimension.rb +54 -0
- data/lib/reports_kits/reports/data/populate_two_dimensions.rb +104 -0
- data/lib/reports_kits/reports/data/utils.rb +178 -0
- data/lib/reports_kits/reports/dimension.rb +27 -0
- data/lib/reports_kits/reports/dimension_with_series.rb +144 -0
- data/lib/reports_kits/reports/filter.rb +29 -0
- data/lib/reports_kits/reports/filter_types/base.rb +48 -0
- data/lib/reports_kits/reports/filter_types/boolean.rb +47 -0
- data/lib/reports_kits/reports/filter_types/datetime.rb +51 -0
- data/lib/reports_kits/reports/filter_types/number.rb +30 -0
- data/lib/reports_kits/reports/filter_types/records.rb +26 -0
- data/lib/reports_kits/reports/filter_types/string.rb +38 -0
- data/lib/reports_kits/reports/filter_with_series.rb +97 -0
- data/lib/reports_kits/reports/generate_autocomplete_method_results.rb +29 -0
- data/lib/reports_kits/reports/generate_autocomplete_results.rb +57 -0
- data/lib/reports_kits/reports/inferrable_configuration.rb +116 -0
- data/lib/reports_kits/reports/model_settings.rb +30 -0
- data/lib/reports_kits/reports/properties.rb +10 -0
- data/lib/reports_kits/reports/properties_to_filter.rb +40 -0
- data/lib/reports_kits/reports/series.rb +121 -0
- data/lib/reports_kits/reports_controller.rb +65 -0
- data/lib/reports_kits/utils.rb +11 -0
- data/lib/reports_kits/value.rb +3 -0
- data/lib/reports_kits/version.rb +3 -0
- data/lib/reports_kits.rb +79 -0
- data/reports_kits.gemspec +26 -0
- data/spec/factories/issue_factory.rb +4 -0
- data/spec/factories/issues_label_factory.rb +4 -0
- data/spec/factories/label_factory.rb +4 -0
- data/spec/factories/pro_repo_factory.rb +5 -0
- data/spec/factories/repo_factory.rb +5 -0
- data/spec/factories/tag_factory.rb +4 -0
- data/spec/fixtures/generate_inputs.yml +254 -0
- data/spec/fixtures/generate_outputs.yml +1216 -0
- data/spec/reports_kit/form_builder_spec.rb +26 -0
- data/spec/reports_kit/relative_time_spec.rb +29 -0
- data/spec/reports_kit/reports/data/generate/contextual_filters_spec.rb +60 -0
- data/spec/reports_kit/reports/data/generate_spec.rb +1371 -0
- data/spec/reports_kit/reports/data/normalize_properties_spec.rb +196 -0
- data/spec/reports_kit/reports/dimension_with_series_spec.rb +67 -0
- data/spec/reports_kit/reports/filter_with_series_spec.rb +39 -0
- data/spec/reports_kit/reports/generate_autocomplete_results_spec.rb +69 -0
- data/spec/spec_helper.rb +77 -0
- data/spec/support/config.rb +41 -0
- data/spec/support/example_data_methods.rb +25 -0
- data/spec/support/factory_girl.rb +5 -0
- data/spec/support/helpers.rb +25 -0
- data/spec/support/models/issue.rb +14 -0
- data/spec/support/models/issues_label.rb +4 -0
- data/spec/support/models/label.rb +5 -0
- data/spec/support/models/pro/repo.rb +5 -0
- data/spec/support/models/pro/special_issue.rb +4 -0
- data/spec/support/models/repo.rb +13 -0
- data/spec/support/models/tag.rb +4 -0
- data/spec/support/schema.rb +39 -0
- metadata +134 -4
@@ -0,0 +1,196 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReportsKit::Reports::Data::NormalizeProperties do
|
4
|
+
describe '#perform' do
|
5
|
+
let(:normalized_properties) { described_class.new(properties).perform }
|
6
|
+
let(:series) { normalized_properties[:series] }
|
7
|
+
let(:context_params) { { foo: 'bar' } }
|
8
|
+
let(:name) { 'Foo' }
|
9
|
+
|
10
|
+
context 'without a series key' do
|
11
|
+
let(:properties) do
|
12
|
+
{
|
13
|
+
measure: 'issue',
|
14
|
+
dimensions: %w(opened_at)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'normalizes' do
|
19
|
+
expect(series).to eq([properties])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'with a series key' do
|
24
|
+
let(:properties) do
|
25
|
+
{
|
26
|
+
series: {
|
27
|
+
measure: 'issue',
|
28
|
+
dimensions: %w(opened_at)
|
29
|
+
}
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'normalizes' do
|
34
|
+
expect(series).to eq([properties[:series]])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with a series array and context_params' do
|
39
|
+
let(:properties) do
|
40
|
+
{
|
41
|
+
series: [{
|
42
|
+
measure: 'issue',
|
43
|
+
dimensions: %w(opened_at)
|
44
|
+
}],
|
45
|
+
context_params: context_params
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'normalizes' do
|
50
|
+
expect(series).to eq([{
|
51
|
+
measure: 'issue',
|
52
|
+
dimensions: %w(opened_at),
|
53
|
+
context_params: context_params
|
54
|
+
}])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with a composite series and context_params' do
|
59
|
+
let(:properties) do
|
60
|
+
{
|
61
|
+
name: name,
|
62
|
+
composite_operator: '%',
|
63
|
+
series: [
|
64
|
+
{
|
65
|
+
measure: 'issue',
|
66
|
+
dimensions: %w(created_at)
|
67
|
+
},
|
68
|
+
{
|
69
|
+
measure: 'tag',
|
70
|
+
dimensions: %w(created_at)
|
71
|
+
}
|
72
|
+
],
|
73
|
+
context_params: context_params
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'copies the context_params to the series' do
|
78
|
+
expect(normalized_properties).to eq({
|
79
|
+
name: name,
|
80
|
+
composite_operator: '%',
|
81
|
+
series: [
|
82
|
+
{
|
83
|
+
measure: 'issue',
|
84
|
+
dimensions: %w(created_at),
|
85
|
+
context_params: context_params
|
86
|
+
},
|
87
|
+
{
|
88
|
+
measure: 'tag',
|
89
|
+
dimensions: %w(created_at),
|
90
|
+
context_params: context_params
|
91
|
+
}
|
92
|
+
],
|
93
|
+
context_params: context_params
|
94
|
+
})
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'with a composite series and context_params' do
|
99
|
+
let(:properties) do
|
100
|
+
{
|
101
|
+
series: [
|
102
|
+
{
|
103
|
+
name: name,
|
104
|
+
composite_operator: '+',
|
105
|
+
series: [
|
106
|
+
{
|
107
|
+
measure: 'issue',
|
108
|
+
dimensions: %w(created_at)
|
109
|
+
}
|
110
|
+
]
|
111
|
+
}
|
112
|
+
],
|
113
|
+
context_params: context_params
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'copies the context_params to the series' do
|
118
|
+
expect(normalized_properties).to eq({
|
119
|
+
series: [
|
120
|
+
{
|
121
|
+
name: name,
|
122
|
+
composite_operator: '+',
|
123
|
+
series: [
|
124
|
+
{
|
125
|
+
measure: 'issue',
|
126
|
+
dimensions: %w(created_at),
|
127
|
+
context_params: context_params
|
128
|
+
}
|
129
|
+
],
|
130
|
+
context_params: context_params
|
131
|
+
}
|
132
|
+
],
|
133
|
+
context_params: context_params
|
134
|
+
})
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'with a composite series, a series, and context_params' do
|
139
|
+
let(:properties) do
|
140
|
+
{
|
141
|
+
series: [
|
142
|
+
{
|
143
|
+
measure: 'issue',
|
144
|
+
dimensions: %w(opened_at)
|
145
|
+
},
|
146
|
+
{
|
147
|
+
name: name,
|
148
|
+
composite_operator: '%',
|
149
|
+
series: [
|
150
|
+
{
|
151
|
+
measure: 'issue',
|
152
|
+
dimensions: %w(created_at)
|
153
|
+
},
|
154
|
+
{
|
155
|
+
measure: 'tag',
|
156
|
+
dimensions: %w(created_at)
|
157
|
+
}
|
158
|
+
]
|
159
|
+
}
|
160
|
+
],
|
161
|
+
context_params: context_params
|
162
|
+
}
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'copies the context_params to the series' do
|
166
|
+
expect(normalized_properties).to eq({
|
167
|
+
series: [
|
168
|
+
{
|
169
|
+
measure: 'issue',
|
170
|
+
dimensions: %w(opened_at),
|
171
|
+
context_params: context_params
|
172
|
+
},
|
173
|
+
{
|
174
|
+
name: name,
|
175
|
+
composite_operator: '%',
|
176
|
+
series: [
|
177
|
+
{
|
178
|
+
measure: 'issue',
|
179
|
+
dimensions: %w(created_at),
|
180
|
+
context_params: context_params
|
181
|
+
},
|
182
|
+
{
|
183
|
+
measure: 'tag',
|
184
|
+
dimensions: %w(created_at),
|
185
|
+
context_params: context_params
|
186
|
+
}
|
187
|
+
],
|
188
|
+
context_params: context_params
|
189
|
+
}
|
190
|
+
],
|
191
|
+
context_params: context_params
|
192
|
+
})
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReportsKit::Reports::DimensionWithSeries do
|
4
|
+
subject { described_class.new(dimension: dimension, series: series) }
|
5
|
+
let(:dimension) { ReportsKit::Reports::Dimension.new(properties) }
|
6
|
+
let(:series) { ReportsKit::Reports::Series.new(measure: 'issue', dimensions: [properties]) }
|
7
|
+
|
8
|
+
describe 'settings' do
|
9
|
+
context 'with a datetime dimension' do
|
10
|
+
let(:properties) { 'opened_at' }
|
11
|
+
|
12
|
+
it 'returns the settings' do
|
13
|
+
expect(subject.settings).to eq({ column: 'issues.opened_at', group: database_adapter.truncate_to_week('issues.opened_at') })
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with a string dimension' do
|
18
|
+
let(:properties) { 'title' }
|
19
|
+
|
20
|
+
it 'returns the settings' do
|
21
|
+
expect(subject.settings).to eq({ column: 'issues.title', group: 'issues.title' })
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with a text dimension' do
|
26
|
+
let(:properties) { 'description' }
|
27
|
+
|
28
|
+
it 'returns the settings' do
|
29
|
+
expect(subject.settings).to eq({ column: 'issues.description', group: 'issues.description' })
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with a belongs_to association dimension' do
|
34
|
+
let(:properties) { 'repo' }
|
35
|
+
|
36
|
+
it 'returns the settings' do
|
37
|
+
expect(subject.settings).to eq({ column: 'issues.repo_id', group: 'issues.repo_id' })
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with a has_many association dimension' do
|
42
|
+
let(:properties) { 'tags' }
|
43
|
+
|
44
|
+
it 'returns the settings' do
|
45
|
+
expect(subject.settings).to eq({ joins: :tags, column: 'tags.id', group: 'issues.issue_id' })
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with a has_many :through association dimension' do
|
50
|
+
let(:properties) { 'labels' }
|
51
|
+
|
52
|
+
it 'returns the settings' do
|
53
|
+
expect(subject.settings).to eq({ joins: :issues_labels, column: 'issues_labels.label_id', group: 'issues_labels.label_id' })
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe ':key_to_label setting' do
|
58
|
+
context 'with a Proc' do
|
59
|
+
let(:properties) { 'titleized_state' }
|
60
|
+
|
61
|
+
it 'returns the result of the Proc' do
|
62
|
+
expect(subject.key_to_label('foo')).to eq('Foo')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReportsKit::Reports::FilterWithSeries do
|
4
|
+
subject { described_class.new(filter: filter, series: series) }
|
5
|
+
let(:filter) { ReportsKit::Reports::Filter.new(properties) }
|
6
|
+
let(:series) { ReportsKit::Reports::Series.new(measure: 'issue', dimensions: %w(repo)) }
|
7
|
+
|
8
|
+
context 'with a datetime filter' do
|
9
|
+
let(:properties) { 'opened_at' }
|
10
|
+
|
11
|
+
it 'returns the settings' do
|
12
|
+
expect(subject.settings).to eq({ column: 'issues.opened_at' })
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'with a belongs_to association filter' do
|
17
|
+
let(:properties) { 'repo' }
|
18
|
+
|
19
|
+
it 'returns the settings' do
|
20
|
+
expect(subject.settings).to eq({ column: 'issues.repo_id' })
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with a has_many association filter' do
|
25
|
+
let(:properties) { 'tags' }
|
26
|
+
|
27
|
+
it 'returns the settings' do
|
28
|
+
expect(subject.settings).to eq({ joins: :tags, column: 'tags.id' })
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with a has_many :through association filter' do
|
33
|
+
let(:properties) { 'labels' }
|
34
|
+
|
35
|
+
it 'returns the settings' do
|
36
|
+
expect(subject.settings).to eq({ joins: :issues_labels, column: 'issues_labels.label_id' })
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReportsKit::Reports::GenerateAutocompleteResults do
|
4
|
+
subject { described_class.new(params, properties).perform }
|
5
|
+
let!(:repo) { create(:repo) }
|
6
|
+
let!(:repo2) { create(:repo) }
|
7
|
+
let!(:issues) do
|
8
|
+
[
|
9
|
+
create(:issue, repo: repo, opened_at: now - 2.weeks),
|
10
|
+
create(:issue, repo: repo2, opened_at: now - 2.weeks),
|
11
|
+
create(:issue, repo: repo, opened_at: now)
|
12
|
+
]
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with valid params' do
|
16
|
+
let(:params) { { key: 'repo' } }
|
17
|
+
let(:properties) do
|
18
|
+
{
|
19
|
+
measure: 'issue',
|
20
|
+
filters: %w(repo),
|
21
|
+
dimensions: %w(opened_at)
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'returns the results' do
|
26
|
+
expect(subject).to match_array([
|
27
|
+
{ id: repo.id, text: repo.to_s },
|
28
|
+
{ id: repo2.id, text: repo2.to_s }
|
29
|
+
])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with a contextual_filter' do
|
34
|
+
context 'with context_params' do
|
35
|
+
let(:params) { { key: 'repo', context_params: { repo_id: repo.id } } }
|
36
|
+
let(:properties) do
|
37
|
+
{
|
38
|
+
measure: 'issue',
|
39
|
+
filters: [{ key: 'repo', contextual_filters: %w(for_repo) }],
|
40
|
+
dimensions: %w(opened_at)
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns the results' do
|
45
|
+
expect(subject).to match_array([
|
46
|
+
{ id: repo.id, text: repo.to_s }
|
47
|
+
])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'without context_params' do
|
52
|
+
let(:params) { { key: 'repo' } }
|
53
|
+
let(:properties) do
|
54
|
+
{
|
55
|
+
measure: 'issue',
|
56
|
+
filters: [{ key: 'repo', contextual_filters: %w(for_repo) }],
|
57
|
+
dimensions: %w(opened_at)
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns the results' do
|
62
|
+
expect(subject).to match_array([
|
63
|
+
{ id: repo.id, text: repo.to_s },
|
64
|
+
{ id: repo2.id, text: repo2.to_s }
|
65
|
+
])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'reports_kit'
|
2
|
+
|
3
|
+
require 'database_cleaner'
|
4
|
+
require 'groupdate'
|
5
|
+
require 'pry'
|
6
|
+
require 'pry-byebug'
|
7
|
+
require 'timecop'
|
8
|
+
require 'support/factory_girl'
|
9
|
+
require 'support/helpers'
|
10
|
+
|
11
|
+
Time.zone = ActiveSupport::TimeZone.new('UTC')
|
12
|
+
ActiveRecord::Base.default_timezone = :utc
|
13
|
+
|
14
|
+
if Gem.loaded_specs.key?('mysql2')
|
15
|
+
REPORTS_KIT_DATABASE_ADAPTER = ReportsKit::Reports::Adapters::Mysql
|
16
|
+
REPORTS_KIT_DATABASE_TYPE = :mysql
|
17
|
+
ActiveRecord::Base.establish_connection(
|
18
|
+
adapter: 'mysql2',
|
19
|
+
host: ENV['MYSQL_HOST'] || 'localhost',
|
20
|
+
database: 'reports_kit_test',
|
21
|
+
username: 'root'
|
22
|
+
)
|
23
|
+
else
|
24
|
+
REPORTS_KIT_DATABASE_ADAPTER = ReportsKit::Reports::Adapters::Postgresql
|
25
|
+
REPORTS_KIT_DATABASE_TYPE = :postgresql
|
26
|
+
ActiveRecord::Base.establish_connection(
|
27
|
+
adapter: 'postgresql',
|
28
|
+
host: ENV['POSTGRESQL_HOST'] || 'localhost',
|
29
|
+
database: 'reports_kit_test',
|
30
|
+
username: 'postgres'
|
31
|
+
)
|
32
|
+
end
|
33
|
+
directory = File.dirname(File.absolute_path(__FILE__))
|
34
|
+
Dir.glob("#{directory}/support/models/*.rb") { |file| require file }
|
35
|
+
Dir.glob("#{directory}/support/models/**/*.rb") { |file| require file }
|
36
|
+
Dir.glob("#{directory}/factories/*.rb") { |file| require file }
|
37
|
+
|
38
|
+
require 'support/config'
|
39
|
+
require 'support/example_data_methods'
|
40
|
+
require 'support/schema'
|
41
|
+
|
42
|
+
RSpec.configure do |config|
|
43
|
+
# ## Mock Framework
|
44
|
+
#
|
45
|
+
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
|
46
|
+
#
|
47
|
+
# config.mock_with :mocha
|
48
|
+
# config.mock_with :flexmock
|
49
|
+
# config.mock_with :rr
|
50
|
+
|
51
|
+
# Run specs in random order to surface order dependencies. If you find an
|
52
|
+
# order dependency and want to debug it, you can fix the order by providing
|
53
|
+
# the seed, which is printed after each run.
|
54
|
+
# --seed 1234
|
55
|
+
config.order = 'random'
|
56
|
+
|
57
|
+
TIMECOP_TIME = Time.utc(2010)
|
58
|
+
config.before(:each) do
|
59
|
+
Timecop.freeze(TIMECOP_TIME)
|
60
|
+
end
|
61
|
+
config.after(:each) do
|
62
|
+
Timecop.return
|
63
|
+
end
|
64
|
+
|
65
|
+
config.before(:suite) do
|
66
|
+
# To support multi-threaded ActiveRecord queries, we need to use :truncation instead of :transaction.
|
67
|
+
DatabaseCleaner.strategy = [:truncation, pre_count: true]
|
68
|
+
end
|
69
|
+
|
70
|
+
config.around(:each) do |example|
|
71
|
+
DatabaseCleaner.cleaning do
|
72
|
+
example.run
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
config.include Helpers
|
77
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
ReportsKit.configure do |config|
|
2
|
+
config.custom_methods = {
|
3
|
+
format_percentage: -> (value) { "#{value.round(0)}%" },
|
4
|
+
add_label_link: -> (data:, properties:, context_record:) {
|
5
|
+
data[:entities].each do |entity|
|
6
|
+
entity.label = "<a href='#'>#{entity.label}</a> Bar" if entity.label
|
7
|
+
end
|
8
|
+
data
|
9
|
+
},
|
10
|
+
add_label_suffix: -> (data:, properties:, context_record:) {
|
11
|
+
data[:entities].each do |entity|
|
12
|
+
entity.label = "#{entity.label} Foo" if entity.label
|
13
|
+
end
|
14
|
+
data
|
15
|
+
},
|
16
|
+
add_context_record_suffix: -> (data:, properties:, context_record:) {
|
17
|
+
data[:entities].each do |entity|
|
18
|
+
entity.label = "#{entity.label} #{context_record}" if entity.label
|
19
|
+
end
|
20
|
+
data
|
21
|
+
},
|
22
|
+
empty_result_set_for_relation: -> (relation) {
|
23
|
+
relation.where('0 = 1')
|
24
|
+
},
|
25
|
+
prepend_column: -> (data:, properties:, context_record:) {
|
26
|
+
values = data[:entities].map do |entity|
|
27
|
+
value = entity.instance.is_a?(Date) ? entity.instance.mday : nil
|
28
|
+
ReportsKit::Value.new(value, value)
|
29
|
+
end
|
30
|
+
new_dataset = {
|
31
|
+
entity: ReportsKit::Entity.new('day_of_month', 'Day of Month', 'day_of_month'),
|
32
|
+
values: values
|
33
|
+
}
|
34
|
+
data[:datasets] = [new_dataset] + data[:datasets]
|
35
|
+
data
|
36
|
+
},
|
37
|
+
all_repo_ids: -> (dimension_keys:, properties:, context_record:) {
|
38
|
+
Repo.pluck(:id)
|
39
|
+
}
|
40
|
+
}
|
41
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class ExampleDataMethods
|
2
|
+
def self.issues_by_opened_at(properties)
|
3
|
+
Issue.group_by_week(:opened_at).count.map { |date, count| [format_date(date), count] }
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.issues_by_opened_at_and_repo(properties)
|
7
|
+
Issue.group_by_week(:opened_at).joins(:repo).group('repos.full_name').count.map do |(date, name), count|
|
8
|
+
[[format_date(date), name], count]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.issues_by_opened_at_with_filters(properties)
|
13
|
+
format = properties[:format]
|
14
|
+
ui_filters = properties[:ui_filters]
|
15
|
+
issues = Issue.group_by_week(:opened_at)
|
16
|
+
issues = issues.where(state: ui_filters[:state]) if ui_filters.try(:[], :state).present?
|
17
|
+
dates_issue_counts = issues.count.map { |date, count| [format_date(date), count] }
|
18
|
+
return dates_issue_counts unless format == 'table'
|
19
|
+
[['Date', 'Issue count']] + dates_issue_counts
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.format_date(date)
|
23
|
+
date.strftime('%b %-d, \'%y')
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Helpers
|
2
|
+
def now
|
3
|
+
Time.zone.now
|
4
|
+
end
|
5
|
+
|
6
|
+
def database_adapter
|
7
|
+
REPORTS_KIT_DATABASE_ADAPTER
|
8
|
+
end
|
9
|
+
|
10
|
+
def format_configuration_time(time)
|
11
|
+
ReportsKit::Reports::Data::Utils.format_configuration_time(time)
|
12
|
+
end
|
13
|
+
|
14
|
+
def format_csv_week_offset(week_offset)
|
15
|
+
ReportsKit::Reports::Data::Utils.format_csv_time((now - week_offset.weeks).beginning_of_week(ReportsKit.configuration.first_day_of_week))
|
16
|
+
end
|
17
|
+
|
18
|
+
def format_day_offset(day_offset)
|
19
|
+
ReportsKit::Reports::Data::Utils.format_display_time((now - day_offset.days))
|
20
|
+
end
|
21
|
+
|
22
|
+
def format_week_offset(week_offset)
|
23
|
+
ReportsKit::Reports::Data::Utils.format_display_time((now - week_offset.weeks).beginning_of_week(ReportsKit.configuration.first_day_of_week))
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Issue < ActiveRecord::Base
|
2
|
+
include ReportsKit::Model
|
3
|
+
|
4
|
+
belongs_to :repo
|
5
|
+
has_many :issues_labels
|
6
|
+
has_many :labels, through: :issues_labels
|
7
|
+
has_many :tags
|
8
|
+
|
9
|
+
reports_kit do
|
10
|
+
aggregation :average_duration, [:average, REPORTS_KIT_DATABASE_TYPE == :mysql ? 'DATEDIFF(closed_at, opened_at)' : '(closed_at::date - opened_at::date)']
|
11
|
+
contextual_filter :for_repo, ->(relation, context_params) { context_params ? relation.where(repo_id: context_params[:repo_id]) : relation }
|
12
|
+
dimension :titleized_state, group: 'issues.state', key_to_label: -> (state) { state.try(:titleize) }
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Repo < ActiveRecord::Base
|
2
|
+
include ReportsKit::Model
|
3
|
+
|
4
|
+
has_many :issues
|
5
|
+
|
6
|
+
reports_kit do
|
7
|
+
contextual_filter :for_repo, ->(relation, context_params) { context_params ? relation.where(id: context_params[:repo_id]) : relation }
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
full_name
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
ActiveRecord::Schema.define do
|
2
|
+
self.verbose = false
|
3
|
+
|
4
|
+
create_table :issues, :force => :cascade do |t|
|
5
|
+
t.integer :repo_id
|
6
|
+
t.string :title
|
7
|
+
t.text :description
|
8
|
+
t.integer :source_user_id
|
9
|
+
t.string :state
|
10
|
+
t.boolean :locked
|
11
|
+
t.datetime :opened_at
|
12
|
+
t.datetime :closed_at
|
13
|
+
t.timestamps
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table :issues_labels, force: :cascade do |t|
|
17
|
+
t.integer :issue_id
|
18
|
+
t.integer :label_id
|
19
|
+
t.timestamps
|
20
|
+
end
|
21
|
+
|
22
|
+
create_table :labels, force: :cascade do |t|
|
23
|
+
t.integer :repo_id
|
24
|
+
t.string :name
|
25
|
+
t.timestamps
|
26
|
+
end
|
27
|
+
|
28
|
+
create_table :repos, :force => :cascade do |t|
|
29
|
+
t.string :full_name
|
30
|
+
t.timestamps
|
31
|
+
end
|
32
|
+
|
33
|
+
create_table :tags, force: :cascade do |t|
|
34
|
+
t.integer :repo_id
|
35
|
+
t.integer :issue_id
|
36
|
+
t.string :name
|
37
|
+
t.timestamps
|
38
|
+
end
|
39
|
+
end
|