lita-standups 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/lita-standups.rb +2 -2
- data/lib/lita/standups/manager.rb +31 -7
- data/lib/lita/standups/mixins/robot.rb +14 -3
- data/lib/lita/standups/models.rb +6 -6
- data/lib/lita/standups/models/base.rb +18 -0
- data/lib/lita/standups/models/standup.rb +4 -2
- data/lib/lita/standups/models/standup_response.rb +4 -2
- data/lib/lita/standups/models/standup_schedule.rb +4 -2
- data/lib/lita/standups/models/standup_session.rb +12 -7
- data/lib/lita/standups/wizards.rb +4 -5
- data/lib/lita/standups/wizards/create_standup.rb +4 -0
- data/lib/lita/standups/wizards/run_standup.rb +0 -2
- data/lita-standups.gemspec +1 -1
- data/spec/lita/standups/manager_spec.rb +25 -2
- data/spec/lita/standups/mixins/robot_spec.rb +3 -3
- data/spec/spec_helper.rb +2 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c6fb95c83938f29cf9d4a66cd0de5d358c326fd
|
4
|
+
data.tar.gz: 6e782535b601fd6c64975ad03ed71f1f7ee99e37
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b916ab7c0626b48c9c72659588c69f905d5e4f5bbe6a6a5367250b2b072b3951d3ab834ea3e12b8f851a9113ff19f59c10445594f10b54975b28c7b8914ba9c6
|
7
|
+
data.tar.gz: c57430753b2cce21b4f5a67150f86a164a69cac87e6448a819370e7ae7928ed6d3bca2369aec69616165bded7c2d9261dbf874d3672c8c0b0651e629cb5ced6e
|
data/lib/lita-standups.rb
CHANGED
@@ -13,7 +13,7 @@ require "lita-wizard"
|
|
13
13
|
require "rufus-scheduler"
|
14
14
|
require "ohm"
|
15
15
|
require "ohm/contrib"
|
16
|
-
require "active_support
|
16
|
+
require "active_support"
|
17
17
|
|
18
18
|
require "lita/handlers/standups"
|
19
19
|
require "lita/standups/wizards"
|
@@ -23,5 +23,5 @@ require "lita/standups/mixins/robot"
|
|
23
23
|
|
24
24
|
Lita::Handlers::Standups.template_root File.expand_path(
|
25
25
|
File.join("..", "..", "templates"),
|
26
|
-
|
26
|
+
__FILE__
|
27
27
|
)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "active_support/core_ext/time"
|
2
|
+
|
1
3
|
module Lita
|
2
4
|
module Standups
|
3
5
|
class Manager
|
@@ -14,19 +16,29 @@ module Lita
|
|
14
16
|
end
|
15
17
|
|
16
18
|
def self.run_schedule(robot:, schedule_id:)
|
19
|
+
Lita.logger.debug "Running scheduled standup for schedule ID=#{schedule_id}"
|
17
20
|
schedule = Models::StandupSchedule[schedule_id]
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
+
Lita.logger.debug "Found scheduled standup: #{schedule.inspect}"
|
22
|
+
session = Lita::Standups::Models::StandupSession.create(
|
23
|
+
standup: schedule.standup,
|
24
|
+
standup_schedule: schedule,
|
21
25
|
recipients: schedule.recipients,
|
22
26
|
room: schedule.channel
|
23
27
|
)
|
28
|
+
Lita.logger.debug "Created session: #{session.inspect}"
|
24
29
|
new(robot: robot, session: session).run
|
30
|
+
rescue Exception => e
|
31
|
+
Lita.logger.debug "Got exception while trying to run schedule ID #{schedule_id}"
|
32
|
+
Lita.logger.debug e.inspect
|
33
|
+
Lita.logger.debug e.backtrace.join("\n")
|
34
|
+
raise e
|
25
35
|
end
|
26
36
|
|
27
37
|
def self.abort_expired_standups(robot:)
|
38
|
+
Lita.logger.debug "Checking for expired standups"
|
28
39
|
Lita::Standups::Models::StandupResponse.find(status: "pending").union(status: "running").each do |response|
|
29
40
|
next unless Time.current - response.created_at > EXPIRATION_TIME
|
41
|
+
Lita.logger.debug "Found expired standup response: #{response.inspect}. Expiring ..."
|
30
42
|
response.expired!
|
31
43
|
response.save
|
32
44
|
Lita::Wizard.cancel_wizard(response.user.id)
|
@@ -36,7 +48,9 @@ module Lita
|
|
36
48
|
end
|
37
49
|
|
38
50
|
def self.complete_finished_standups(robot:)
|
39
|
-
Lita
|
51
|
+
Lita.logger.debug "Checking for finished sesssions"
|
52
|
+
Lita::Standups::Models::StandupSession.find(status: "completed", results_sent: "0").each do |session|
|
53
|
+
Lita.logger.debug "Found finished session: #{session.inspect}. Posting results ..."
|
40
54
|
new(robot: robot, session: session).post_results
|
41
55
|
end
|
42
56
|
end
|
@@ -57,6 +71,7 @@ module Lita
|
|
57
71
|
end
|
58
72
|
|
59
73
|
def run
|
74
|
+
Lita.logger.debug "Running standup for session ID=#{session.id}"
|
60
75
|
session.running!
|
61
76
|
session.save
|
62
77
|
session.recipients.each { |recipient| ask_questions(recipient) }
|
@@ -64,20 +79,29 @@ module Lita
|
|
64
79
|
|
65
80
|
def ask_questions(recipient)
|
66
81
|
user = Lita::User.fuzzy_find(recipient)
|
82
|
+
Lita.logger.debug "Running the wizard for recipient #{recipient} (#{user.inspect})"
|
67
83
|
response = Models::StandupResponse.create(
|
68
84
|
standup_session_id: session.id,
|
69
85
|
user_id: user.id
|
70
86
|
)
|
71
87
|
dummy_source = Lita::Source.new(user: user, room: nil, private_message: true)
|
72
88
|
dummy_message = Lita::Message.new(robot, '', dummy_source)
|
73
|
-
|
89
|
+
begin
|
90
|
+
Wizards::RunStandup.start robot, dummy_message, 'response_id' => response.id
|
91
|
+
rescue Exception => e
|
92
|
+
Lita.logger.debug "Got exception while trying to run the standup with #{recipient}"
|
93
|
+
Lita.logger.debug e.inspect
|
94
|
+
Lita.logger.debug e.backtrace.join("\n")
|
95
|
+
response.aborted!
|
96
|
+
response.save
|
97
|
+
end
|
74
98
|
end
|
75
99
|
|
76
100
|
def post_results
|
77
|
-
return if session.results_sent
|
101
|
+
return if session.results_sent == "1"
|
78
102
|
message = "The standup '#{standup.name}' has finished. Here's what everyone posted:\n\n#{session.report_message}"
|
79
103
|
robot.send_message room, message
|
80
|
-
session.results_sent =
|
104
|
+
session.results_sent = "1"
|
81
105
|
session.save
|
82
106
|
end
|
83
107
|
|
@@ -19,13 +19,18 @@ module Lita
|
|
19
19
|
|
20
20
|
def schedule_standups
|
21
21
|
return unless scheduler_enabled?
|
22
|
+
Lita.logger.debug "Unscheduling any existing jobs"
|
22
23
|
scheduler.jobs.each(&:unschedule)
|
23
|
-
|
24
|
+
Lita.logger.debug "Scheduling standup status jobs"
|
25
|
+
scheduler.cron '*/15 * * * * *', tags: [:standup_schedules, :abort_expired] do |job|
|
26
|
+
Ohm.redis = Redic.new(Ohm.redis.url)
|
24
27
|
Lita::Standups::Manager.abort_expired_standups(robot: self)
|
25
28
|
end
|
26
|
-
scheduler.cron '* * * * *', tags: [:standup_schedules, :complete_finished] do |job|
|
29
|
+
scheduler.cron '*/15 * * * * *', tags: [:standup_schedules, :complete_finished] do |job|
|
30
|
+
Ohm.redis = Redic.new(Ohm.redis.url)
|
27
31
|
Lita::Standups::Manager.complete_finished_standups(robot: self)
|
28
32
|
end
|
33
|
+
Lita.logger.debug "Scheduling standups"
|
29
34
|
Models::StandupSchedule.all.each do |standup_schedule|
|
30
35
|
schedule_standup(standup_schedule)
|
31
36
|
end
|
@@ -35,21 +40,27 @@ module Lita
|
|
35
40
|
return unless scheduler_enabled?
|
36
41
|
scheduler.cron standup_schedule.cron_line, schedule_id: standup_schedule.id,
|
37
42
|
tags: [:standup_schedules, "standup_schedule_#{standup_schedule.id}"] do |job|
|
38
|
-
|
43
|
+
Ohm.redis = Redic.new(Ohm.redis.url)
|
44
|
+
Lita.logger.debug "Calling run_schedule on Manager for #{job.opts[:schedule_id]}"
|
45
|
+
Lita::Standups::Manager.run_schedule(robot: self, schedule_id: job.opts[:schedule_id])
|
39
46
|
end
|
40
47
|
end
|
41
48
|
|
42
49
|
def unschedule_standup(standup_schedule)
|
43
50
|
return unless scheduler_enabled?
|
51
|
+
Lita.logger.debug "Unscheduling standup scheduled #{standup_schedule.id}"
|
44
52
|
scheduler.jobs(tags: [:standup_schedules, "standup_schedule_#{standup_schedule.id}"]).each(&:unschedule)
|
45
53
|
end
|
46
54
|
|
47
55
|
def run_standup(standup_id, recipients, room_id)
|
48
56
|
if scheduler_enabled?
|
49
57
|
scheduler.in "5s", tags: [:standup_schedules, :run_standup] do |job|
|
58
|
+
Ohm.redis = Redic.new(Ohm.redis.url)
|
59
|
+
Lita.logger.debug "Calling run on Manager for standup #{standup_id} (recipients: #{recipients.join(", ")}"
|
50
60
|
Lita::Standups::Manager.run(robot: self, standup_id: standup_id, recipients: recipients, room: room_id)
|
51
61
|
end
|
52
62
|
else
|
63
|
+
Lita.logger.debug "Calling run on Manager for standup #{standup_id} (recipients: #{recipients.join(", ")}"
|
53
64
|
Lita::Standups::Manager.run(robot: self, standup_id: standup_id, recipients: recipients, room: room_id)
|
54
65
|
end
|
55
66
|
end
|
data/lib/lita/standups/models.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
module Lita
|
2
2
|
module Standups
|
3
3
|
module Models
|
4
|
-
extend ActiveSupport::Autoload
|
5
|
-
|
6
|
-
autoload :Standup
|
7
|
-
autoload :StandupResponse
|
8
|
-
autoload :StandupSchedule
|
9
|
-
autoload :StandupSession
|
10
4
|
end
|
11
5
|
end
|
12
6
|
end
|
7
|
+
|
8
|
+
require "lita/standups/models/base"
|
9
|
+
require "lita/standups/models/standup"
|
10
|
+
require "lita/standups/models/standup_response"
|
11
|
+
require "lita/standups/models/standup_schedule"
|
12
|
+
require "lita/standups/models/standup_session"
|
@@ -1,7 +1,9 @@
|
|
1
|
+
require "lita/standups/models/standup_schedule"
|
2
|
+
|
1
3
|
module Lita
|
2
4
|
module Standups
|
3
5
|
module Models
|
4
|
-
class Standup <
|
6
|
+
class Standup < Base
|
5
7
|
|
6
8
|
include Ohm::Callbacks
|
7
9
|
include Ohm::Timestamps
|
@@ -10,7 +12,7 @@ module Lita
|
|
10
12
|
attribute :name
|
11
13
|
attribute :questions, Type::Array
|
12
14
|
|
13
|
-
collection :schedules, StandupSchedule, :standup
|
15
|
+
collection :schedules, "Lita::Standups::Models::StandupSchedule", :standup
|
14
16
|
|
15
17
|
def summary
|
16
18
|
"#{name} (ID: #{id}) - #{questions.size} question(s)"
|
@@ -1,7 +1,9 @@
|
|
1
|
+
require "lita/standups/models/standup_session"
|
2
|
+
|
1
3
|
module Lita
|
2
4
|
module Standups
|
3
5
|
module Models
|
4
|
-
class StandupResponse <
|
6
|
+
class StandupResponse < Base
|
5
7
|
|
6
8
|
include Ohm::Callbacks
|
7
9
|
include Ohm::Timestamps
|
@@ -11,7 +13,7 @@ module Lita
|
|
11
13
|
attribute :user_id
|
12
14
|
attribute :answers, Type::Array
|
13
15
|
|
14
|
-
reference :standup_session, StandupSession
|
16
|
+
reference :standup_session, "Lita::Standups::Models::StandupSession"
|
15
17
|
|
16
18
|
index :status
|
17
19
|
index :user_id
|
@@ -1,7 +1,9 @@
|
|
1
|
+
require "lita/standups/models/standup"
|
2
|
+
|
1
3
|
module Lita
|
2
4
|
module Standups
|
3
5
|
module Models
|
4
|
-
class StandupSchedule <
|
6
|
+
class StandupSchedule < Base
|
5
7
|
|
6
8
|
include Ohm::Callbacks
|
7
9
|
include Ohm::Timestamps
|
@@ -13,7 +15,7 @@ module Lita
|
|
13
15
|
attribute :recipients, Type::Array
|
14
16
|
attribute :channel
|
15
17
|
|
16
|
-
reference :standup, Standup
|
18
|
+
reference :standup, "Lita::Standups::Models::Standup"
|
17
19
|
|
18
20
|
def cron_line
|
19
21
|
[
|
@@ -1,7 +1,11 @@
|
|
1
|
+
require "lita/standups/models/standup"
|
2
|
+
require "lita/standups/models/standup_schedule"
|
3
|
+
require "lita/standups/models/standup_response"
|
4
|
+
|
1
5
|
module Lita
|
2
6
|
module Standups
|
3
7
|
module Models
|
4
|
-
class StandupSession <
|
8
|
+
class StandupSession < Base
|
5
9
|
|
6
10
|
include Ohm::Callbacks
|
7
11
|
include Ohm::Timestamps
|
@@ -11,18 +15,18 @@ module Lita
|
|
11
15
|
attribute :room
|
12
16
|
attribute :counts, Type::Hash
|
13
17
|
attribute :recipients, Type::Array
|
14
|
-
attribute :results_sent
|
18
|
+
attribute :results_sent
|
15
19
|
|
16
|
-
reference :standup, Standup
|
17
|
-
reference :standup_schedule, StandupSchedule
|
18
|
-
collection :standup_responses, StandupResponse, :standup_session
|
20
|
+
reference :standup, "Lita::Standups::Models::Standup"
|
21
|
+
reference :standup_schedule, "Lita::Standups::Models::StandupSchedule"
|
22
|
+
collection :standup_responses, "Lita::Standups::Models::StandupResponse", :standup_session
|
19
23
|
|
20
24
|
index :status
|
21
25
|
index :results_sent
|
22
26
|
|
23
27
|
def before_create
|
24
28
|
self.status = 'pending'
|
25
|
-
self.results_sent =
|
29
|
+
self.results_sent = "0"
|
26
30
|
end
|
27
31
|
|
28
32
|
%w(pending running completed).each do |status_name|
|
@@ -32,12 +36,13 @@ module Lita
|
|
32
36
|
end
|
33
37
|
|
34
38
|
def update_status
|
35
|
-
|
39
|
+
counts = { 'total' => 0, 'finished' => 0 }
|
36
40
|
standup_responses.each do |r|
|
37
41
|
counts[r.status] = counts[r.status].to_i + 1
|
38
42
|
counts['total'] = counts['total'] + 1
|
39
43
|
counts['finished'] = counts['finished'] + 1 if r.finished?
|
40
44
|
end
|
45
|
+
self.counts = counts
|
41
46
|
completed! if counts['total'] == counts['finished']
|
42
47
|
save
|
43
48
|
end
|
@@ -1,11 +1,10 @@
|
|
1
1
|
module Lita
|
2
2
|
module Standups
|
3
3
|
module Wizards
|
4
|
-
extend ActiveSupport::Autoload
|
5
|
-
|
6
|
-
autoload :CreateStandup
|
7
|
-
autoload :RunStandup
|
8
|
-
autoload :ScheduleStandup
|
9
4
|
end
|
10
5
|
end
|
11
6
|
end
|
7
|
+
|
8
|
+
require "lita/standups/wizards/create_standup"
|
9
|
+
require "lita/standups/wizards/run_standup"
|
10
|
+
require "lita/standups/wizards/schedule_standup"
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "active_support/core_ext/object/blank"
|
2
|
+
|
1
3
|
module Lita
|
2
4
|
module Standups
|
3
5
|
module Wizards
|
@@ -11,10 +13,12 @@ module Lita
|
|
11
13
|
multiline: true
|
12
14
|
|
13
15
|
def finish_wizard
|
16
|
+
Lita.logger.debug "Finishing wizard CreateStandup for user #{user_id}"
|
14
17
|
@standup = Models::Standup.create(
|
15
18
|
name: value_for(:name),
|
16
19
|
questions: value_for(:questions).to_s.split("\n").map(&:strip).map(&:presence).compact
|
17
20
|
)
|
21
|
+
Lita.logger.debug "Created standup: #{@standup.summary}"
|
18
22
|
end
|
19
23
|
|
20
24
|
def final_message
|
data/lita-standups.gemspec
CHANGED
@@ -32,6 +32,15 @@ describe Lita::Standups::Manager do
|
|
32
32
|
end.to change { Lita::Standups::Models::StandupSession.all.count }.by(1)
|
33
33
|
end
|
34
34
|
|
35
|
+
it "should log exceptions and raise them when trying to run a schedule" do
|
36
|
+
allow_any_instance_of(described_class).to receive(:run).and_raise(Exception)
|
37
|
+
allow(Lita.logger).to receive(:debug)
|
38
|
+
expect(Lita.logger).to receive(:debug).at_least(:once).with(/^Got exception/)
|
39
|
+
expect do
|
40
|
+
described_class.run_schedule(robot: robot, schedule_id: "1")
|
41
|
+
end.to raise_exception(Exception)
|
42
|
+
end
|
43
|
+
|
35
44
|
it "should mark expired reponses as expired" do
|
36
45
|
responses = [Lita::Standups::Models::StandupResponse[1], Lita::Standups::Models::StandupResponse[2]]
|
37
46
|
responses[0].created_at = Time.now - 100_000
|
@@ -63,6 +72,20 @@ describe Lita::Standups::Manager do
|
|
63
72
|
expect(Lita::Standups::Wizards::RunStandup).to receive(:start)
|
64
73
|
described_class.run(robot: robot, standup_id: "1", recipients: %w(1), room: "#a")
|
65
74
|
end
|
75
|
+
|
76
|
+
it "should log exceptions when ask_question raises an exception" do
|
77
|
+
allow(Lita::Standups::Wizards::RunStandup).to receive(:start).and_raise(Exception)
|
78
|
+
allow(Lita.logger).to receive(:debug)
|
79
|
+
expect(Lita.logger).to receive(:debug).at_least(:once).with(/^Got exception/)
|
80
|
+
described_class.run(robot: robot, standup_id: "1", recipients: %w(1), room: "#a")
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should mark the response as aborted when ask_question raises an exception" do
|
84
|
+
allow(Lita::Standups::Wizards::RunStandup).to receive(:start).and_raise(Exception)
|
85
|
+
expect_any_instance_of(Lita::Standups::Models::StandupResponse).to \
|
86
|
+
receive(:aborted!).once
|
87
|
+
described_class.run(robot: robot, standup_id: "1", recipients: %w(1), room: "#a")
|
88
|
+
end
|
66
89
|
end
|
67
90
|
|
68
91
|
context "posting results" do
|
@@ -77,12 +100,12 @@ describe Lita::Standups::Manager do
|
|
77
100
|
allow(robot).to receive(:send_message)
|
78
101
|
expect do
|
79
102
|
described_class.new(robot: robot, session: session).post_results
|
80
|
-
end.to change { Lita::Standups::Models::StandupSession[1].results_sent }.to(
|
103
|
+
end.to change { Lita::Standups::Models::StandupSession[1].results_sent }.to("1")
|
81
104
|
end
|
82
105
|
|
83
106
|
it "sholdn't post anything if already posted" do
|
84
107
|
session = Lita::Standups::Models::StandupSession[1]
|
85
|
-
session.results_sent =
|
108
|
+
session.results_sent = "1"
|
86
109
|
session.save
|
87
110
|
expect(robot).to receive(:send_message).never
|
88
111
|
described_class.new(robot: robot, session: session).post_results
|
@@ -41,7 +41,7 @@ describe "Robot Mixin" do
|
|
41
41
|
it "should try to run a standup inline" do
|
42
42
|
expect(scheduler).to receive(:in).never
|
43
43
|
expect(Lita::Standups::Manager).to receive(:run).once
|
44
|
-
robot.run_standup("standup_id", "recipients", "room_id")
|
44
|
+
robot.run_standup("standup_id", ["recipients"], "room_id")
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -75,7 +75,7 @@ describe "Robot Mixin" do
|
|
75
75
|
it "should try to run a standup in the scheduler" do
|
76
76
|
expect(scheduler).to receive(:in).once
|
77
77
|
expect(Lita::Standups::Manager).to receive(:run).never
|
78
|
-
robot.run_standup("standup_id", "recipients", "room_id")
|
78
|
+
robot.run_standup("standup_id", ["recipients"], "room_id")
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
@@ -100,7 +100,7 @@ describe "Robot Mixin" do
|
|
100
100
|
end
|
101
101
|
|
102
102
|
it "should run a standup inside the scheduler" do
|
103
|
-
robot.run_standup("standup_id", "recipients", "room_id")
|
103
|
+
robot.run_standup("standup_id", ["recipients"], "room_id")
|
104
104
|
expect(Lita::Standups::Manager).to receive(:run)
|
105
105
|
scheduler.jobs(tags: [:run_standup]).first.call
|
106
106
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -12,6 +12,8 @@ require "lita/rspec"
|
|
12
12
|
|
13
13
|
Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f }
|
14
14
|
|
15
|
+
Ohm.redis = Redic.new("redis://127.0.0.1:6379/13")
|
16
|
+
|
15
17
|
# A compatibility mode is provided for older plugins upgrading from Lita 3. Since this plugin
|
16
18
|
# was generated with Lita 4, the compatibility mode should be left disabled.
|
17
19
|
Lita.version_3_compatibility_mode = false
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lita-standups
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cristian Bica
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-06-
|
11
|
+
date: 2016-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: lita
|
@@ -255,6 +255,7 @@ files:
|
|
255
255
|
- lib/lita/standups/manager.rb
|
256
256
|
- lib/lita/standups/mixins/robot.rb
|
257
257
|
- lib/lita/standups/models.rb
|
258
|
+
- lib/lita/standups/models/base.rb
|
258
259
|
- lib/lita/standups/models/standup.rb
|
259
260
|
- lib/lita/standups/models/standup_response.rb
|
260
261
|
- lib/lita/standups/models/standup_schedule.rb
|