Standupguy 0.0.6
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/.coveralls.yml +1 -0
- data/.gitignore +16 -0
- data/.hound.yml +2 -0
- data/.semver +5 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/Guardfile +33 -0
- data/LICENSE.txt +22 -0
- data/README.md +33 -0
- data/Rakefile +15 -0
- data/Standupguy.gemspec +36 -0
- data/bin/standupguy +21 -0
- data/lib/Standupguy.rb +225 -0
- data/lib/Standupguy/report.email.haml +4 -0
- data/lib/Standupguy/report.html.haml +6 -0
- data/lib/Standupguy/report.txt.haml +4 -0
- data/lib/Standupguy/version.rb +3 -0
- data/spec/.rspec +2 -0
- data/spec/core_spec.rb +73 -0
- data/spec/data_methods_spec.rb +53 -0
- data/spec/item_spec.rb +55 -0
- data/spec/report_spec.rb +92 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/standupguy_spec.rb +1 -0
- data/test/.gitkeep +0 -0
- metadata +274 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5de7e3f00059222502c7d1da5129d2daddfb5853
|
4
|
+
data.tar.gz: 4d83f6f677e20f529241204e17bbf1582d617791
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cfa537dc8fe381f18395e6f45498613815bea3bdd30aea4fe76853329d316e18c94bdaa682648ca6b674a1cb1fb62e7dc4c5a3bb36890795a744cc7d15ccd591
|
7
|
+
data.tar.gz: eca38c2cb3fb5d0b30bcb3b587f7daddce6914ca0ae4b3b43de80839550869d5ef2aae50f9ffe4232c0b4032f0789316f729019d863cca5614c63ad3ddb44d7e
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
repo_token: SMdgGBpI2HGDSJE9f3G6t4jYDtyhgafvf
|
data/.gitignore
ADDED
data/.hound.yml
ADDED
data/.semver
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
5
|
+
# rspec may be run, below are examples of the most common uses.
|
6
|
+
# * bundler: 'bundle exec rspec'
|
7
|
+
# * bundler binstubs: 'bin/rspec'
|
8
|
+
# * spring: 'bin/rsspec' (This will use spring if running and you have
|
9
|
+
# installed the spring binstubs per the docs)
|
10
|
+
# * zeus: 'zeus rspec' (requires the server to be started separetly)
|
11
|
+
# * 'just' rspec: 'rspec'
|
12
|
+
guard :rspec, cmd: 'bundle exec rspec' do
|
13
|
+
watch(%r{^spec/.+_spec\.rb$})
|
14
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
15
|
+
watch('spec/spec_helper.rb') { "spec" }
|
16
|
+
|
17
|
+
# Rails example
|
18
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
19
|
+
watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
20
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
21
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
22
|
+
watch('config/routes.rb') { "spec/routing" }
|
23
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
24
|
+
watch('spec/rails_helper.rb') { "spec" }
|
25
|
+
|
26
|
+
# Capybara features specs
|
27
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
28
|
+
|
29
|
+
# Turnip features and steps
|
30
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
31
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
32
|
+
end
|
33
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Adam Panzer
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
[](https://coveralls.io/r/apanzerj/Standupguy) [](https://travis-ci.org/apanzerj/Standupguy)
|
2
|
+
|
3
|
+
# Standupguy
|
4
|
+
|
5
|
+
Quickly and easily manage your daily standup from the command line.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Install it yourself as:
|
10
|
+
|
11
|
+
$ gem install Standupguy
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
### Adding an item
|
16
|
+
|
17
|
+
$ standupguy https://foo.zendesk.com/tickets/2
|
18
|
+
|
19
|
+
$ standupguy I did a thing today
|
20
|
+
|
21
|
+
### Viewing your standup
|
22
|
+
|
23
|
+
$ standupguy --report TEXT
|
24
|
+
|
25
|
+
$ standupguy --report HTML
|
26
|
+
|
27
|
+
## Contributing
|
28
|
+
|
29
|
+
1. Fork it ( https://github.com/[my-github-username]/Standupguy/fork )
|
30
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
31
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
32
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
33
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
# Default directory to look in is `/specs`
|
5
|
+
# Run with `rake spec`
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
7
|
+
task.rspec_opts = ['--color', '--format', 'documentation']
|
8
|
+
end
|
9
|
+
|
10
|
+
RSpec::Core::RakeTask.new(:sublime) do |task|
|
11
|
+
task.rspec_opts = ['--no-color']
|
12
|
+
end
|
13
|
+
|
14
|
+
task :default => :spec
|
15
|
+
|
data/Standupguy.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'Standupguy/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "Standupguy"
|
8
|
+
spec.version = Standupguy::VERSION
|
9
|
+
spec.authors = ["Adam Panzer"]
|
10
|
+
spec.email = ["apanzerj@gmail.com"]
|
11
|
+
spec.summary = %q{Manage your daily activity or "Stand Up" quickly and easily}
|
12
|
+
spec.description = %q{Integrated with Zendesk. Manage your daily StandUp report easily.}
|
13
|
+
spec.homepage = "https://github.com/apanzerj/Standupguy"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "byebug"
|
24
|
+
spec.add_development_dependency "rspec"
|
25
|
+
spec.add_development_dependency "rspec-nc"
|
26
|
+
spec.add_development_dependency "guard"
|
27
|
+
spec.add_development_dependency "guard-rspec"
|
28
|
+
spec.add_development_dependency "semver"
|
29
|
+
spec.add_development_dependency "mocha"
|
30
|
+
spec.add_development_dependency "webmock"
|
31
|
+
spec.add_development_dependency "coveralls"
|
32
|
+
|
33
|
+
spec.add_runtime_dependency "zendesk_api"
|
34
|
+
spec.add_runtime_dependency "launchy"
|
35
|
+
spec.add_runtime_dependency "haml"
|
36
|
+
end
|
data/bin/standupguy
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'Standupguy'
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
options = {}
|
6
|
+
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.banner = 'Usage: standupguy [options]'
|
9
|
+
|
10
|
+
opts.on('-r', '--report=FORMAT', 'Show an HTML report') do |r|
|
11
|
+
options[:report] = r
|
12
|
+
end
|
13
|
+
|
14
|
+
opts.on('-d', '--date=YYYY-MM-DD', 'Date of standup. ALL for all') do |date|
|
15
|
+
options[:date] = date
|
16
|
+
end
|
17
|
+
end.parse!
|
18
|
+
|
19
|
+
options.merge!(item: ARGV.join(' ')) unless ARGV.empty?
|
20
|
+
|
21
|
+
Standupguy::Core.new(options)
|
data/lib/Standupguy.rb
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
require "zendesk_api"
|
2
|
+
require "tempfile"
|
3
|
+
require "haml"
|
4
|
+
require "launchy"
|
5
|
+
require "open-uri"
|
6
|
+
|
7
|
+
# StandUpGuy manages your daily standups by giving you a simple command line
|
8
|
+
# interface to add new items. It grabs contextual information from the items
|
9
|
+
# in your standup and fetches additional information from available sources.
|
10
|
+
#
|
11
|
+
# Currently supported external sources:
|
12
|
+
#
|
13
|
+
# 1. Zendesk
|
14
|
+
#
|
15
|
+
# To be implemented
|
16
|
+
#
|
17
|
+
# 1. Jira
|
18
|
+
#
|
19
|
+
module Standupguy
|
20
|
+
# Generic methods for pulling data from standup.json
|
21
|
+
module DataMethods
|
22
|
+
def date_key(date = :today)
|
23
|
+
date = date == :today ? DateTime.now : DateTime.strptime(date, "%Y-%m-%d")
|
24
|
+
date.strftime("%Y-%m-%d")
|
25
|
+
rescue ArgumentError
|
26
|
+
date = :today
|
27
|
+
retry
|
28
|
+
end
|
29
|
+
|
30
|
+
def filename
|
31
|
+
File.join(Standupguy::Core::DATA_ROOT, "standup.json")
|
32
|
+
end
|
33
|
+
|
34
|
+
def load_data
|
35
|
+
@current_standup = JSON.load(File.open(filename))
|
36
|
+
end
|
37
|
+
|
38
|
+
def write_data(current_standup)
|
39
|
+
File.open(filename, "w") do |f|
|
40
|
+
f << JSON.dump(current_standup)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Generic methods that were moved from bin/standupguy to here
|
46
|
+
# in order to better test this code. Mostly init stuff.
|
47
|
+
class Core
|
48
|
+
DATA_ROOT = File.join(ENV["HOME"], ".standupguy")
|
49
|
+
def initialize(options)
|
50
|
+
first_time! unless Dir.exist?(DATA_ROOT)
|
51
|
+
|
52
|
+
if options[:item]
|
53
|
+
item = Standupguy::Item.new
|
54
|
+
item.add_to_today(options[:item])
|
55
|
+
item.save
|
56
|
+
date = DateTime.now.strftime("%Y-%m-%d")
|
57
|
+
options = { report: "TEXT", date: date }.merge(options)
|
58
|
+
end
|
59
|
+
|
60
|
+
report(options).show unless options[:report].nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
def report(options)
|
64
|
+
case options[:report]
|
65
|
+
when "HTML"
|
66
|
+
Standupguy::HTMLReport.new(options[:date])
|
67
|
+
when "TEXT"
|
68
|
+
Standupguy::TextReport.new(options[:date])
|
69
|
+
when "EMAIL"
|
70
|
+
Standupguy::EmailReport.new(options[:date])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def first_time!
|
75
|
+
Kernel.puts("First time running...\nCreating data directory")
|
76
|
+
Dir.mkdir(DATA_ROOT)
|
77
|
+
File.open(File.join(DATA_ROOT, "standup.json"), "a+").close
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Generic methods for all types of report.
|
82
|
+
class Report
|
83
|
+
include DataMethods
|
84
|
+
attr_accessor :current_standup, :date
|
85
|
+
|
86
|
+
def initialize(date = nil)
|
87
|
+
@current_standup = JSON.load(File.open(filename))
|
88
|
+
date ||= "ALL"
|
89
|
+
@date = date == "ALL" ? :all : date_key(date)
|
90
|
+
end
|
91
|
+
|
92
|
+
def link
|
93
|
+
"file:///#{file.path}"
|
94
|
+
end
|
95
|
+
|
96
|
+
def template(file)
|
97
|
+
spec = Gem::Specification.find_by_name("Standupguy")
|
98
|
+
gem_root = spec.gem_dir
|
99
|
+
File.read(File.join(gem_root, "lib", "Standupguy", file))
|
100
|
+
end
|
101
|
+
|
102
|
+
def data(date = :all)
|
103
|
+
scope = @current_standup
|
104
|
+
scope = { date => @current_standup[date] } unless date == :all
|
105
|
+
scope
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# HTML Formatted report. Creates a tempfile that is deleted in 5 seconds.
|
110
|
+
# Tempfile is opened in browser using Launchy.
|
111
|
+
class HTMLReport < Report
|
112
|
+
def show
|
113
|
+
File.write(file, render)
|
114
|
+
file.close
|
115
|
+
Launchy.open link
|
116
|
+
Kernel.sleep 5
|
117
|
+
file.unlink
|
118
|
+
end
|
119
|
+
|
120
|
+
def render
|
121
|
+
::Haml::Engine.new(template("report.html.haml")).
|
122
|
+
render(Object.new, standup: data(@date))
|
123
|
+
end
|
124
|
+
|
125
|
+
def file
|
126
|
+
@file ||= Tempfile.new(["report", ".html"])
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Text formatted report. Output to STDOUT
|
131
|
+
class TextReport < Report
|
132
|
+
def show
|
133
|
+
puts render
|
134
|
+
end
|
135
|
+
|
136
|
+
def render
|
137
|
+
::Haml::Engine.new(template("report.txt.haml")).
|
138
|
+
render(Object.new, standup: data(@date))
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Basically a text report that is outputted to a mailto link. Only supports
|
143
|
+
# the Mac OS operating system at the moment.
|
144
|
+
class EmailReport < TextReport
|
145
|
+
def show
|
146
|
+
@date = !date.nil? ? date : date_key(:today)
|
147
|
+
body = render
|
148
|
+
parameters = ::URI.encode_www_form([
|
149
|
+
["subject", "StandUp for #{date_key(:today)}"],
|
150
|
+
["body", body]])
|
151
|
+
link = "mailto:?#{parameters}"
|
152
|
+
Kernel.system("open '#{link}'") if mac?
|
153
|
+
end
|
154
|
+
|
155
|
+
def render
|
156
|
+
::Haml::Engine.new(template("report.email.haml")).
|
157
|
+
render(Object.new, standup: data(@date))
|
158
|
+
end
|
159
|
+
|
160
|
+
def mac?
|
161
|
+
Launchy::Detect::HostOs.new.host_os.start_with?("darwin")
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Basic Item class. Each line in your standup is an Item.
|
166
|
+
class Item
|
167
|
+
include DataMethods
|
168
|
+
|
169
|
+
attr_accessor :data
|
170
|
+
|
171
|
+
def method_missing(method, *args)
|
172
|
+
return unless [:description=, :name=, :date=].include?(method)
|
173
|
+
method = method.to_s.chop.to_sym
|
174
|
+
@data[method] = args.first
|
175
|
+
end
|
176
|
+
|
177
|
+
def save
|
178
|
+
current_standup = load_data
|
179
|
+
current_standup ||= { date_key => [] }
|
180
|
+
data_exists = current_standup.keys.include?(date_key)
|
181
|
+
current_standup[date_key] = [] unless data_exists
|
182
|
+
current_standup[date_key] << @data
|
183
|
+
write_data(current_standup)
|
184
|
+
end
|
185
|
+
|
186
|
+
def add_to_today(item)
|
187
|
+
@data ||= { description: "", name: "", date: "" }
|
188
|
+
ticket = TicketUrl.new(item)
|
189
|
+
if ticket.valid?
|
190
|
+
zendesk_ticket = client(ticket.subdomain).tickets.find(id: ticket.id)
|
191
|
+
self.description = "#{item} => (#{zendesk_ticket.subject})"
|
192
|
+
else
|
193
|
+
self.description = item
|
194
|
+
end
|
195
|
+
|
196
|
+
self.name = `whoami`.chop
|
197
|
+
self.date = key
|
198
|
+
end
|
199
|
+
|
200
|
+
def client(subdomain)
|
201
|
+
@client ||= ZendeskAPI::Client.new do |config|
|
202
|
+
config.url = "https://#{subdomain}.zendesk.com/api/v2"
|
203
|
+
config.username = ENV["zendesk_user"]
|
204
|
+
config.token = ENV["zendesk_token"]
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
TicketUrl = Struct.new(:url, :subdomain, :id) do
|
209
|
+
CLASSIC_TICKET = %r{https?:\/\/(.*?)\.zendesk.com\/[a-z].*?\/(.*)}
|
210
|
+
LOTUS_TICKET = \
|
211
|
+
%r{https?:\/\/(.*?)\.zendesk.com\/agent\/#?\/?tickets\/(\d+)\/?.*?}
|
212
|
+
def initialize(url)
|
213
|
+
[LOTUS_TICKET, CLASSIC_TICKET].each do |pattern|
|
214
|
+
subdomain, id = url.downcase.scan(pattern).flatten
|
215
|
+
super(url, subdomain, id)
|
216
|
+
return if self.valid?
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def valid?
|
221
|
+
!(id.nil? && subdomain.nil?)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
data/spec/.rspec
ADDED
data/spec/core_spec.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require_relative "../lib/Standupguy"
|
3
|
+
|
4
|
+
describe Standupguy::Core do
|
5
|
+
before do
|
6
|
+
Standupguy::Item.any_instance.stubs(:save)
|
7
|
+
@file = create_test_file!
|
8
|
+
end
|
9
|
+
|
10
|
+
subject{ {} }
|
11
|
+
it "takes options" do
|
12
|
+
Standupguy::Core.new(subject)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "can generate a TEXT report" do
|
16
|
+
subject.merge!(report: "TEXT")
|
17
|
+
Standupguy::TextReport.any_instance.expects(:show)
|
18
|
+
Standupguy::Core.new(subject)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can generate an HTML report" do
|
22
|
+
subject.merge!(report: "HTML")
|
23
|
+
Standupguy::HTMLReport.any_instance.expects(:show)
|
24
|
+
Standupguy::Core.new(subject)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can generate an EMAIL report" do
|
28
|
+
subject.merge!(report: "EMAIL")
|
29
|
+
Standupguy::EmailReport.any_instance.expects(:show)
|
30
|
+
Standupguy::Core.new(subject)
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "adding an item" do
|
34
|
+
it "can add an item" do
|
35
|
+
subject.merge!(item: "Test Item", report: nil)
|
36
|
+
Standupguy::Core.new(subject)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "runs a text report for today" do
|
40
|
+
subject.merge!(:item => "Test Item")
|
41
|
+
report = stub
|
42
|
+
Standupguy::TextReport.expects(:new).
|
43
|
+
with(DateTime.now.strftime("%Y-%m-%d")).returns(report)
|
44
|
+
report.expects(:show)
|
45
|
+
Standupguy::Core.new(subject)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#first_time!" do
|
50
|
+
before do
|
51
|
+
Kernel.stubs(:puts)
|
52
|
+
Dir.stubs(:exist?).returns(false)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "is called when no directory exists" do
|
56
|
+
Standupguy::Core.any_instance.expects(:first_time!)
|
57
|
+
Standupguy::Core.new({})
|
58
|
+
end
|
59
|
+
|
60
|
+
it "creates the directory and makes the file" do
|
61
|
+
File.expects(:open).
|
62
|
+
with(File.join(Standupguy::Core::DATA_ROOT, "standup.json"), "a+").
|
63
|
+
returns(@file)
|
64
|
+
Dir.expects(:mkdir)
|
65
|
+
Standupguy::Core.new({})
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
after do
|
70
|
+
@file.close
|
71
|
+
@file.unlink
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require_relative "../lib/Standupguy"
|
3
|
+
include Standupguy::DataMethods
|
4
|
+
|
5
|
+
describe Standupguy::DataMethods do
|
6
|
+
describe "#date_key" do
|
7
|
+
it "returns the current date formatted string when give :today" do
|
8
|
+
expect(date_key(:today)).to be_a_kind_of(String)
|
9
|
+
expect(date_key(:today)).to match(/\d{4}-\d{2}-\d{2}/)
|
10
|
+
expect(date_key(:today)).to eq(DateTime.now.strftime("%Y-%m-%d"))
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns the date formatted sting when given same" do
|
14
|
+
expect(date_key("2014-10-10")).to be_a_kind_of(String)
|
15
|
+
expect(date_key("2014-10-10")).to match(/\d{4}-\d{2}-\d{2}/)
|
16
|
+
expect(date_key("2014-10-10")).to eq("2014-10-10")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns today when given a non date formatted string" do
|
20
|
+
expect(date_key("foo")).to eq(DateTime.now.strftime("%Y-%m-%d"))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#filename" do
|
25
|
+
it do
|
26
|
+
result = File.join(Standupguy::Core::DATA_ROOT, "standup.json")
|
27
|
+
expect(filename).to eq(result)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#load_data" do
|
32
|
+
before do
|
33
|
+
@file = Tempfile.new("foo")
|
34
|
+
stubs(filename: @file.path)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "reads an existing file" do
|
38
|
+
File.write(@file, '{"foo": "bar"}')
|
39
|
+
expect(load_data).to eq({"foo" => "bar"})
|
40
|
+
end
|
41
|
+
|
42
|
+
it "writes the current standup" do
|
43
|
+
write_data({"foo" => "bar"})
|
44
|
+
expect(File.read(@file)).to eq('{"foo":"bar"}')
|
45
|
+
File.delete(@file)
|
46
|
+
end
|
47
|
+
|
48
|
+
after do
|
49
|
+
@file.close
|
50
|
+
@file.unlink
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/spec/item_spec.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require_relative "../lib/Standupguy"
|
3
|
+
|
4
|
+
describe Standupguy::Item do
|
5
|
+
describe "#add_to_today" do
|
6
|
+
subject(:item) { Standupguy::Item.new }
|
7
|
+
|
8
|
+
context "for zendesk tickets" do
|
9
|
+
before do
|
10
|
+
expect_zendesk("foo", "api/v2/tickets/1").
|
11
|
+
to_return(headers: {"Content-Type" => "application/json"}, body: JSON.dump("ticket" => {"subject" => "test ticket"}))
|
12
|
+
item.add_to_today("https://foo.zendesk.com/tickets/1")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "includes the ticket subject in the description" do
|
16
|
+
expect(item.data[:description]).to match(/test ticket/)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "includes the original url" do
|
20
|
+
expect(item.data[:description]).to match(/foo.zendesk.com\/tickets\/1/)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "for non-zendesk tickets" do
|
25
|
+
it "takes an item" do
|
26
|
+
item.add_to_today("foob")
|
27
|
+
expect(item.data[:description]).to match(/foob/)
|
28
|
+
expect(item.data[:name]).to match(`whoami`.chop)
|
29
|
+
expect(item.data[:date]).to match(key)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#save" do
|
35
|
+
before do
|
36
|
+
@datafile = create_test_file!
|
37
|
+
end
|
38
|
+
|
39
|
+
subject(:item) do
|
40
|
+
test_item = Standupguy::Item.new
|
41
|
+
test_item.add_to_today("foo")
|
42
|
+
test_item
|
43
|
+
end
|
44
|
+
|
45
|
+
it "writes a file" do
|
46
|
+
item.save
|
47
|
+
expect_datafile(@datafile, %r{foo})
|
48
|
+
end
|
49
|
+
|
50
|
+
after do
|
51
|
+
@datafile.close
|
52
|
+
@datafile.unlink
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/spec/report_spec.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require_relative "../lib/Standupguy"
|
3
|
+
|
4
|
+
describe Standupguy::Report do
|
5
|
+
before do
|
6
|
+
@datafile = create_test_file!
|
7
|
+
@item = Standupguy::Item.new
|
8
|
+
@item.add_to_today("foob a doob")
|
9
|
+
@item.save
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#initialize" do
|
13
|
+
subject(:report) { Standupguy::Report.new }
|
14
|
+
|
15
|
+
it "reads current standup data" do
|
16
|
+
expect(report.current_standup[key].first["description"]).to match(@item.data[:description])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#link" do
|
21
|
+
subject(:report) { Standupguy::HTMLReport.new }
|
22
|
+
|
23
|
+
it "returns a link" do
|
24
|
+
expect(report.link).to match(%r{file:///})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#data" do
|
29
|
+
let(:report) { Standupguy::Report.new }
|
30
|
+
|
31
|
+
it "returns the current_standup without a date" do
|
32
|
+
expect(report.data).to be(report.current_standup)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "returns scoped data when passed a date" do
|
36
|
+
report.instance_variable_set(:@current_standup, {"2014-10-10"=>["foo"], "2014-10-11"=>[nil]})
|
37
|
+
expect(report.data("2014-10-10").first).to eq(["2014-10-10", ["foo"]])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#mac?" do
|
42
|
+
subject { Standupguy::EmailReport.new }
|
43
|
+
it "tells me if I'm on a mac" do
|
44
|
+
host_os = Launchy::Detect::HostOs.new.host_os
|
45
|
+
expect(subject.mac?).to be(host_os.start_with?("darwin"))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
[:html, :txt, :email].each do |format|
|
50
|
+
describe "#show" do
|
51
|
+
subject(:report) do
|
52
|
+
case format
|
53
|
+
when :html then Standupguy::HTMLReport.new
|
54
|
+
when :txt then Standupguy::TextReport.new
|
55
|
+
when :email then Standupguy::EmailReport.new
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
before do
|
60
|
+
Launchy.stubs(:open)
|
61
|
+
Standupguy::EmailReport.any_instance.stubs(:mac?).returns(true)
|
62
|
+
Kernel.stubs(:sleep)
|
63
|
+
Kernel.stubs(:system)
|
64
|
+
Standupguy::TextReport.send(:define_method, :puts) { |*args| "" }
|
65
|
+
end
|
66
|
+
|
67
|
+
describe format.to_s do
|
68
|
+
it "calls #render" do
|
69
|
+
report.expects(:render).returns("foo")
|
70
|
+
report.show
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#render" do
|
74
|
+
it "renders a HAML template" do
|
75
|
+
@file = "= key"
|
76
|
+
report.expects(:template).with("report.#{format}.haml").returns(@file)
|
77
|
+
expect(report.render).to match(key)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "is rendered with the current_standup" do
|
81
|
+
expect(report.render).to match(/foob a doob/)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
after do
|
89
|
+
@datafile.close
|
90
|
+
@datafile.unlink
|
91
|
+
end
|
92
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'webmock/rspec'
|
2
|
+
require 'json'
|
3
|
+
require 'byebug'
|
4
|
+
require 'coveralls'
|
5
|
+
Coveralls::Output.silent = true
|
6
|
+
Coveralls.wear!
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.run_all_when_everything_filtered = true
|
10
|
+
config.mock_with :mocha
|
11
|
+
config.order = 'random'
|
12
|
+
end
|
13
|
+
|
14
|
+
def expect_zendesk(subdomain, endpoint)
|
15
|
+
ENV["zendesk_user"] = "foo@bar.com"
|
16
|
+
ENV["zendesk_token"] = "123abc"
|
17
|
+
crazy_piece = "foo%40bar.com%2Ftoken:123abc"
|
18
|
+
stub_request(:get, %r{#{subdomain}.zendesk.com.#{endpoint}})
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_test_file!(temp_file = true)
|
22
|
+
datafile = Tempfile.new(["standup", ".json"], File.join(`pwd`.chop, "test")) if temp_file
|
23
|
+
datafile ||= File.join(`pwd`.chop, "test", "standup.json")
|
24
|
+
stub_filename(datafile)
|
25
|
+
end
|
26
|
+
|
27
|
+
def stub_filename(datafile)
|
28
|
+
path = datafile.is_a?(String) ? datafile : datafile.path
|
29
|
+
Standupguy::DataMethods.stubs(:filename).returns(path)
|
30
|
+
Standupguy::Report.any_instance.stubs(:filename).returns(path)
|
31
|
+
Standupguy::Item.any_instance.stubs(:filename).returns(path)
|
32
|
+
datafile
|
33
|
+
end
|
34
|
+
|
35
|
+
def expect_datafile(file, pattern)
|
36
|
+
data = File.read(file.path)
|
37
|
+
expect(data).to match(pattern)
|
38
|
+
end
|
39
|
+
|
40
|
+
def key(date=:today)
|
41
|
+
return DateTime.now.strftime("%Y-%m-%d") if date==:today
|
42
|
+
return DateTime.strptime(date,"%Y-%m-%d") if date.is_a?(String)
|
43
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "spec_helper"
|
data/test/.gitkeep
ADDED
File without changes
|
metadata
ADDED
@@ -0,0 +1,274 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: Standupguy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Panzer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-11-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: byebug
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec-nc
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: guard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: guard-rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: semver
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: mocha
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: webmock
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: coveralls
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: zendesk_api
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :runtime
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: launchy
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :runtime
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: haml
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :runtime
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
209
|
+
description: Integrated with Zendesk. Manage your daily StandUp report easily.
|
210
|
+
email:
|
211
|
+
- apanzerj@gmail.com
|
212
|
+
executables:
|
213
|
+
- standupguy
|
214
|
+
extensions: []
|
215
|
+
extra_rdoc_files: []
|
216
|
+
files:
|
217
|
+
- ".coveralls.yml"
|
218
|
+
- ".gitignore"
|
219
|
+
- ".hound.yml"
|
220
|
+
- ".semver"
|
221
|
+
- ".travis.yml"
|
222
|
+
- Gemfile
|
223
|
+
- Guardfile
|
224
|
+
- LICENSE.txt
|
225
|
+
- README.md
|
226
|
+
- Rakefile
|
227
|
+
- Standupguy.gemspec
|
228
|
+
- bin/standupguy
|
229
|
+
- lib/Standupguy.rb
|
230
|
+
- lib/Standupguy/report.email.haml
|
231
|
+
- lib/Standupguy/report.html.haml
|
232
|
+
- lib/Standupguy/report.txt.haml
|
233
|
+
- lib/Standupguy/version.rb
|
234
|
+
- spec/.rspec
|
235
|
+
- spec/core_spec.rb
|
236
|
+
- spec/data_methods_spec.rb
|
237
|
+
- spec/item_spec.rb
|
238
|
+
- spec/report_spec.rb
|
239
|
+
- spec/spec_helper.rb
|
240
|
+
- spec/standupguy_spec.rb
|
241
|
+
- test/.gitkeep
|
242
|
+
homepage: https://github.com/apanzerj/Standupguy
|
243
|
+
licenses:
|
244
|
+
- MIT
|
245
|
+
metadata: {}
|
246
|
+
post_install_message:
|
247
|
+
rdoc_options: []
|
248
|
+
require_paths:
|
249
|
+
- lib
|
250
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
251
|
+
requirements:
|
252
|
+
- - ">="
|
253
|
+
- !ruby/object:Gem::Version
|
254
|
+
version: '0'
|
255
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
256
|
+
requirements:
|
257
|
+
- - ">="
|
258
|
+
- !ruby/object:Gem::Version
|
259
|
+
version: '0'
|
260
|
+
requirements: []
|
261
|
+
rubyforge_project:
|
262
|
+
rubygems_version: 2.2.2
|
263
|
+
signing_key:
|
264
|
+
specification_version: 4
|
265
|
+
summary: Manage your daily activity or "Stand Up" quickly and easily
|
266
|
+
test_files:
|
267
|
+
- spec/.rspec
|
268
|
+
- spec/core_spec.rb
|
269
|
+
- spec/data_methods_spec.rb
|
270
|
+
- spec/item_spec.rb
|
271
|
+
- spec/report_spec.rb
|
272
|
+
- spec/spec_helper.rb
|
273
|
+
- spec/standupguy_spec.rb
|
274
|
+
- test/.gitkeep
|