boardie 0.0.1

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.
@@ -0,0 +1,5 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ db/boardie.db
5
+ config/config.yml
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+ gem "json"
3
+ gem "sinatra"
4
+ gem "sinatra-static-assets"
5
+ gem "faraday"
6
+ gem "faraday_middleware"
7
+ gem "typhoeus"
8
+ gem "emk-sinatra-url-for"
9
+ gem "data_mapper"
10
+ gem "dm-sqlite-adapter"
11
+ gem "sqlite3"
@@ -0,0 +1,90 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.2.8)
5
+ bcrypt-ruby (3.0.1)
6
+ data_mapper (1.2.0)
7
+ dm-aggregates (~> 1.2.0)
8
+ dm-constraints (~> 1.2.0)
9
+ dm-core (~> 1.2.0)
10
+ dm-migrations (~> 1.2.0)
11
+ dm-serializer (~> 1.2.0)
12
+ dm-timestamps (~> 1.2.0)
13
+ dm-transactions (~> 1.2.0)
14
+ dm-types (~> 1.2.0)
15
+ dm-validations (~> 1.2.0)
16
+ data_objects (0.10.8)
17
+ addressable (~> 2.1)
18
+ dm-aggregates (1.2.0)
19
+ dm-core (~> 1.2.0)
20
+ dm-constraints (1.2.0)
21
+ dm-core (~> 1.2.0)
22
+ dm-core (1.2.0)
23
+ addressable (~> 2.2.6)
24
+ dm-do-adapter (1.2.0)
25
+ data_objects (~> 0.10.6)
26
+ dm-core (~> 1.2.0)
27
+ dm-migrations (1.2.0)
28
+ dm-core (~> 1.2.0)
29
+ dm-serializer (1.2.1)
30
+ dm-core (~> 1.2.0)
31
+ fastercsv (~> 1.5.4)
32
+ json (~> 1.6.1)
33
+ json_pure (~> 1.6.1)
34
+ multi_json (~> 1.0.3)
35
+ dm-sqlite-adapter (1.2.0)
36
+ dm-do-adapter (~> 1.2.0)
37
+ do_sqlite3 (~> 0.10.6)
38
+ dm-timestamps (1.2.0)
39
+ dm-core (~> 1.2.0)
40
+ dm-transactions (1.2.0)
41
+ dm-core (~> 1.2.0)
42
+ dm-types (1.2.1)
43
+ bcrypt-ruby (~> 3.0.0)
44
+ dm-core (~> 1.2.0)
45
+ fastercsv (~> 1.5.4)
46
+ json (~> 1.6.1)
47
+ multi_json (~> 1.0.3)
48
+ stringex (~> 1.3.0)
49
+ uuidtools (~> 2.1.2)
50
+ dm-validations (1.2.0)
51
+ dm-core (~> 1.2.0)
52
+ do_sqlite3 (0.10.8)
53
+ data_objects (= 0.10.8)
54
+ emk-sinatra-url-for (0.2.1)
55
+ sinatra (>= 0.9.1.1)
56
+ faraday (0.7.6)
57
+ addressable (~> 2.2)
58
+ multipart-post (~> 1.1)
59
+ rack (~> 1.1)
60
+ fastercsv (1.5.5)
61
+ json (1.6.7)
62
+ json_pure (1.6.7)
63
+ multi_json (1.0.4)
64
+ multipart-post (1.1.5)
65
+ rack (1.4.1)
66
+ rack-protection (1.2.0)
67
+ rack
68
+ sinatra (1.3.2)
69
+ rack (~> 1.3, >= 1.3.6)
70
+ rack-protection (~> 1.2)
71
+ tilt (~> 1.3, >= 1.3.3)
72
+ sinatra-static-assets (1.0.4)
73
+ sinatra (>= 1.1.0)
74
+ sqlite3 (1.3.6)
75
+ stringex (1.3.3)
76
+ tilt (1.3.3)
77
+ uuidtools (2.1.3)
78
+
79
+ PLATFORMS
80
+ ruby
81
+
82
+ DEPENDENCIES
83
+ data_mapper
84
+ dm-sqlite-adapter
85
+ emk-sinatra-url-for
86
+ faraday
87
+ json
88
+ sinatra
89
+ sinatra-static-assets
90
+ sqlite3
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2011 James Turnbull <james@lovedthanlost.net>
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,46 @@
1
+ Boardie
2
+ =======
3
+
4
+ Author
5
+ ------
6
+
7
+ James Turnbull <james@lovedthanlost.net>
8
+
9
+ Prerequistes
10
+ ------------
11
+
12
+ * Sintra
13
+ * Datamapper
14
+ * Sqlite3
15
+
16
+ Installation
17
+ ------------
18
+
19
+ $ sudo gem install boardie
20
+
21
+ Usage
22
+ -----
23
+
24
+ Usage: boardie [options] ...
25
+
26
+ Common options:
27
+ -v, --version Display version
28
+ -h, --help Display this screen
29
+
30
+ The configuration file, `config/config.yml` should contain
31
+ values for:
32
+
33
+ redmine_site: 'https://support.example.com'
34
+ redmine_key: abcde12334
35
+ redmine_project: example_project
36
+ inprogress_quota: 6
37
+
38
+ The `inprogress_quota` indicates the max number of issues that can be in progress at a time.
39
+
40
+ An example file is in the `config` directory.
41
+
42
+ License
43
+ -------
44
+
45
+ See LICENSE file.
46
+
@@ -0,0 +1,7 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ # Migrate DB
5
+ task :migrate do
6
+ DataMapper.auto_migrate!
7
+ end
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright 2012, James Turnbull
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
19
+
20
+ require 'rubygems'
21
+ require 'optparse'
22
+ require 'boardie'
23
+ require 'version'
24
+
25
+ options = {}
26
+
27
+ optparse = OptionParser.new do |opts|
28
+ # Set a banner, displayed at the top
29
+ # of the help screen.
30
+ opts.banner = 'Usage: boardie [options] ...'
31
+
32
+ opts.separator ""
33
+ opts.separator "Common options:"
34
+
35
+ opts.on_tail('-v', '--version', 'Display version' ) do
36
+ puts Boardie::VERSION
37
+ exit
38
+ end
39
+
40
+ opts.on_tail('-h', '--help', 'Display this screen' ) do
41
+ puts opts
42
+ exit
43
+ end
44
+ end
45
+
46
+ begin
47
+ optparse.parse!
48
+ Boardie::Application.run!
49
+ rescue OptionParser::InvalidArgument, OptionParser::InvalidOption, OptionParser::MissingArgument
50
+ puts $!.to_s
51
+ puts optparse
52
+ exit
53
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "boardie"
7
+ s.version = Boardie::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = "James Turnbull"
10
+ s.email = "james@lovedthanlost.net"
11
+ s.homepage = ""
12
+ s.summary = %q{Simple status display board for Redmine}
13
+ s.description = %q{Simple status display board for Redmine}
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+ s.add_dependency(%q<rest-client>, [">= 0"])
19
+ s.add_dependency(%q<json>, [">= 0"])
20
+ s.add_dependency(%q<sinatra>, [">= 0"])
21
+ s.add_dependency(%q<sinatra-static-assets>, [">= 0"])
22
+ s.add_dependency(%q<emk-sinatra-url-for>, [">= 0"])
23
+ s.add_dependency(%q<sqlite3>, [">= 0"])
24
+ s.add_dependency(%q<data_mapper>, [">= 0"])
25
+ s.add_dependency(%q<dm-sqlite-adapter>, [">= 0"])
26
+ s.add_dependency(%q<faraday>, [">= 0"])
27
+ s.add_dependency(%q<faraday_middleware>, [">= 0"])
28
+ s.add_dependency(%q<typhoeus>, [">= 0"])
29
+ end
30
+
@@ -0,0 +1,7 @@
1
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "lib")))
2
+
3
+ require 'boardie'
4
+
5
+ use Rack::ShowExceptions
6
+
7
+ run Boardie::Application.new
@@ -0,0 +1,4 @@
1
+ redmine_site: 'https://support.example.com'
2
+ redmine_key: abcde12334
3
+ redmine_project: example_project
4
+ inprogress_quota: 6
@@ -0,0 +1 @@
1
+ === Database
@@ -0,0 +1,197 @@
1
+ require 'sinatra'
2
+ require 'sinatra/url_for'
3
+ require 'sinatra/static_assets'
4
+ require 'faraday'
5
+ require 'faraday_middleware'
6
+ require 'typhoeus'
7
+ require 'data_mapper'
8
+ require 'json'
9
+ require 'yaml'
10
+
11
+ def load_configuration(file, name)
12
+ if !File.exist?(file)
13
+ puts "There's no configuration file at #{file}!"
14
+ exit!
15
+ end
16
+ Boardie.const_set(name, YAML.load_file(file))
17
+ end
18
+
19
+ module Boardie
20
+ class Application < Sinatra::Base
21
+
22
+ register Sinatra::StaticAssets
23
+
24
+ configure :development do
25
+ load_configuration("config/config.yml", "APP_CONFIG")
26
+ end
27
+
28
+ configure :production do
29
+ log = File.new("log/production.log", "a")
30
+ STDOUT.reopen(log)
31
+ STDERR.reopen(log)
32
+ load_configuration("config/config.yml", "APP_CONFIG")
33
+ end
34
+
35
+ enable :logging, :dump_errors, :raise_errors
36
+ DataMapper.setup(:default, "sqlite3:db/boardie.db")
37
+ enable :show_exceptions
38
+
39
+ class Ticket
40
+ include DataMapper::Resource
41
+
42
+ property :id, Serial
43
+ property :ticket_id, Integer, :key => true
44
+ property :status_id, Integer
45
+ property :status_name, String
46
+ property :subject, String, :length => 250
47
+ property :assigned_to, String
48
+ property :workstream, String
49
+ property :updated_on, Date
50
+
51
+ validates_presence_of :ticket_id
52
+ end
53
+
54
+ DataMapper.finalize
55
+ DataMapper.auto_upgrade!
56
+
57
+ before do
58
+ @app_name = "Boardie"
59
+ get_issues
60
+ end
61
+
62
+ error do
63
+ @error = "Sorry there was a nasty error! Please let Operations know that: " + env['sinatra.error']
64
+ erb :error
65
+ end
66
+
67
+ not_found do
68
+ "Page not found"
69
+ end
70
+
71
+ get '/' do
72
+ expires 180, :public, :must_revalidate
73
+ issues
74
+ erb :index
75
+ end
76
+
77
+ get %r{/stream/(.+)} do |name|
78
+ expires 180, :public, :must_revalidate
79
+ @onpoint = Ticket.all(:ticket_id => 15355).first.assigned_to
80
+ if @workstreams.include? name
81
+ closed_count(name)
82
+ @stream_issues = Ticket.all(:workstream => name, :status_id.not => 5, :status_id.not => 6, :status_id.not => 7)
83
+ erb :stream
84
+ else
85
+ status 404
86
+ end
87
+ end
88
+
89
+ get %r{/engineer/(.+)} do |name|
90
+ expires 180, :public, :must_revalidate
91
+ @onpoint = Ticket.all(:ticket_id => 15355).first.assigned_to
92
+ if @engineers.include? name
93
+ @engineer_issues = Ticket.all(:assigned_to => name, :status_id.not => 5, :status_id.not => 6, :status_id.not => 7)
94
+ erb :engineer
95
+ else
96
+ status 404
97
+ end
98
+ end
99
+
100
+ helpers do
101
+
102
+ def cycle
103
+ %w{even odd}[@_cycle = ((@_cycle || -1) + 1) % 2]
104
+ end
105
+
106
+ CYCLE = %w{even odd}
107
+
108
+ def cycle_fully_sick
109
+ CYCLE[@_cycle = ((@_cycle || -1) + 1) % 2]
110
+ end
111
+
112
+ def get_issues
113
+ @site = APP_CONFIG["redmine_site"]
114
+
115
+ redmine_data = []
116
+ conn = Faraday.new(:url => @site) do |faraday|
117
+ faraday.adapter :typhoeus
118
+ faraday.use Faraday::Response::Logger
119
+ end
120
+
121
+ (1..5).each do |page|
122
+ response = conn.get "/issues.json" do |request|
123
+ request.params['limit'] = 100
124
+ request.params['key'] = "#{APP_CONFIG["redmine_key"]}"
125
+ request.params['project_id'] = "#{APP_CONFIG["redmine_project"]}"
126
+ request.params['page'] = page
127
+ request.params['status_id'] = '*'
128
+ end
129
+
130
+ redmine_data << JSON.parse(response.body)['issues']
131
+ end
132
+
133
+ # No matter its location numerically we always grab who is on point.
134
+ response = conn.get "/issues/15355.json" do |request|
135
+ request.params['key'] = "#{APP_CONFIG["redmine_key"]}"
136
+ request.params['project_id'] = "#{APP_CONFIG["redmine_project"]}"
137
+ end
138
+
139
+ redmine_data << JSON.parse(response.body)['issue']
140
+
141
+ redmine_data.flatten.each do |issue|
142
+ create_record(issue)
143
+ end
144
+
145
+ ws = Ticket.all(:fields => [:workstream], :unique => true, :workstream.not => nil, :workstream.not => "", :status_id.not => 5)
146
+ @workstreams = []
147
+ ws.each do |stream|
148
+ @workstreams << stream.workstream
149
+ end
150
+
151
+ oe = Ticket.all(:fields => [:assigned_to], :unique => true, :assigned_to.not => nil, :assigned_to.not => "", :status_id.not => 5)
152
+ @engineers = []
153
+ oe.each do |engine|
154
+ @engineers << engine.assigned_to
155
+ end
156
+ end
157
+
158
+ def closed_count(stream)
159
+ @site = APP_CONFIG["redmine_site"]
160
+ redmine_data = Ticket.all(:status_id => 5, :workstream => stream)
161
+ @closed_count = redmine_data.count
162
+ end
163
+
164
+ def create_record(issue)
165
+ status_id, status_name = issue["status"]["id"], issue["status"]["name"]
166
+ if issue["assigned_to"]
167
+ assigned = issue["assigned_to"]["name"]
168
+ else
169
+ assigned = nil
170
+ end
171
+ ws = issue["custom_fields"].detect { |f| f["id"] == 38 }
172
+ ws = ws["value"] unless ws == nil
173
+ ws = nil if ws == ""
174
+ ticket = Ticket.first_or_create(:ticket_id => issue["id"]).update(
175
+ :ticket_id => issue["id"],
176
+ :subject => issue["subject"],
177
+ :status_id => status_id,
178
+ :status_name => status_name,
179
+ :assigned_to => assigned,
180
+ :workstream => ws,
181
+ :updated_on => issue['updated_on'])
182
+ end
183
+
184
+ def issues
185
+ @issues = Ticket.all
186
+ @backlog = Ticket.all(:status_id => '8') + Ticket.all(:status_id => '10') + Ticket.all(:status_id => '17') & Ticket.all(:assigned_to => nil)
187
+ @blocked = Ticket.all(:status_id => '11') + Ticket.all(:status_id => '12')
188
+ @inprogress = Ticket.all(:status_id => '8') & Ticket.all(:assigned_to.not => nil)
189
+ @overquota = true if @inprogress.count > (APP_CONFIG["inprogress_quota"] * @engineers.count)
190
+ @review = Ticket.all(:status_id => '14')
191
+ @prod = Ticket.all(:status_id => '18')
192
+ @quota = APP_CONFIG['inprogress_quota']
193
+ @onpoint = Ticket.all(:ticket_id => 15355).first.assigned_to
194
+ end
195
+ end
196
+ end
197
+ end