tp-cli 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.
- checksums.yaml +7 -0
- data/.envrc.example +1 -0
- data/.gitignore +41 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +72 -0
- data/LICENSE.txt +21 -0
- data/README.md +35 -0
- data/Rakefile +82 -0
- data/bin/tp-cli +6 -0
- data/lib/config.rb +33 -0
- data/lib/tp_cli.rb +80 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/tp_cli_spec.rb +254 -0
- data/tp-cli.gemspec +41 -0
- metadata +95 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: ce630488e4d4188bb23c516089800c16085a8798
|
|
4
|
+
data.tar.gz: 02b1ae5362d5960b9ab778bdb367a2b2db13ff31
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 1bb00b7d38a2b603e3c9385e129b17e27ae522daeab40e8259cb9934da1e531a85531ba5f29152db16d18b047392d1a346d344b70aa7277f9ec3cef26e6a6b15
|
|
7
|
+
data.tar.gz: 8a72a3208ed0de576867a25142979e8ea24163296e3acefd9d369d5f6ac40cc217df9fe8045058cf064921a9670d338e9811123d7bd9d2004f4f39663f5fbaad
|
data/.envrc.example
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ruby ./lib/tp_cli.rb
|
data/.gitignore
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
/.config
|
|
4
|
+
/coverage/
|
|
5
|
+
/InstalledFiles
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/spec/examples.txt
|
|
9
|
+
/test/tmp/
|
|
10
|
+
/test/version_tmp/
|
|
11
|
+
/tmp/
|
|
12
|
+
|
|
13
|
+
## Specific to RubyMotion:
|
|
14
|
+
.dat*
|
|
15
|
+
.repl_history
|
|
16
|
+
build/
|
|
17
|
+
|
|
18
|
+
## Documentation cache and generated files:
|
|
19
|
+
/.yardoc/
|
|
20
|
+
/_yardoc/
|
|
21
|
+
/doc/
|
|
22
|
+
/rdoc/
|
|
23
|
+
|
|
24
|
+
## Environment normalisation:
|
|
25
|
+
/.bundle/
|
|
26
|
+
/vendor/bundle
|
|
27
|
+
/lib/bundler/man/
|
|
28
|
+
.envrc
|
|
29
|
+
|
|
30
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
31
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
32
|
+
Gemfile.lock
|
|
33
|
+
.ruby-version
|
|
34
|
+
.ruby-gemset
|
|
35
|
+
/corundum/
|
|
36
|
+
|
|
37
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
38
|
+
.rvmrc
|
|
39
|
+
|
|
40
|
+
config/timepulse.yml
|
|
41
|
+
.DS_Store
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
tp-cli (0.0.1)
|
|
5
|
+
typhoeus (~> 0.8)
|
|
6
|
+
valise (~> 1.1)
|
|
7
|
+
|
|
8
|
+
GEM
|
|
9
|
+
remote: https://rubygems.org/
|
|
10
|
+
specs:
|
|
11
|
+
calibrate (0.0.1)
|
|
12
|
+
caliph (0.3.1)
|
|
13
|
+
corundum (0.6.0)
|
|
14
|
+
bundler
|
|
15
|
+
caliph (~> 0.3)
|
|
16
|
+
mattock (~> 0.9)
|
|
17
|
+
paint (~> 0.8.7)
|
|
18
|
+
rspec (>= 2.0)
|
|
19
|
+
simplecov (>= 0.5.4)
|
|
20
|
+
simplecov-json (>= 0.2)
|
|
21
|
+
diff-lcs (1.2.5)
|
|
22
|
+
docile (1.1.5)
|
|
23
|
+
ethon (0.8.0)
|
|
24
|
+
ffi (>= 1.3.0)
|
|
25
|
+
ffi (1.9.10)
|
|
26
|
+
json (1.8.3)
|
|
27
|
+
mattock (0.10.0)
|
|
28
|
+
calibrate (~> 0.0.1)
|
|
29
|
+
caliph (~> 0.3.1)
|
|
30
|
+
rake (~> 10.0)
|
|
31
|
+
tilt (> 0)
|
|
32
|
+
valise (~> 1.1.1)
|
|
33
|
+
paint (0.8.7)
|
|
34
|
+
rake (10.4.2)
|
|
35
|
+
rspec (3.3.0)
|
|
36
|
+
rspec-core (~> 3.3.0)
|
|
37
|
+
rspec-expectations (~> 3.3.0)
|
|
38
|
+
rspec-mocks (~> 3.3.0)
|
|
39
|
+
rspec-core (3.3.2)
|
|
40
|
+
rspec-support (~> 3.3.0)
|
|
41
|
+
rspec-expectations (3.3.1)
|
|
42
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
43
|
+
rspec-support (~> 3.3.0)
|
|
44
|
+
rspec-mocks (3.3.2)
|
|
45
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
46
|
+
rspec-support (~> 3.3.0)
|
|
47
|
+
rspec-support (3.3.0)
|
|
48
|
+
simplecov (0.10.0)
|
|
49
|
+
docile (~> 1.1.0)
|
|
50
|
+
json (~> 1.8)
|
|
51
|
+
simplecov-html (~> 0.10.0)
|
|
52
|
+
simplecov-html (0.10.0)
|
|
53
|
+
simplecov-json (0.2)
|
|
54
|
+
json
|
|
55
|
+
simplecov
|
|
56
|
+
tilt (2.0.1)
|
|
57
|
+
typhoeus (0.8.0)
|
|
58
|
+
ethon (>= 0.8.0)
|
|
59
|
+
valise (1.1.4)
|
|
60
|
+
|
|
61
|
+
PLATFORMS
|
|
62
|
+
ruby
|
|
63
|
+
|
|
64
|
+
DEPENDENCIES
|
|
65
|
+
bundler (~> 1.10)
|
|
66
|
+
corundum
|
|
67
|
+
rake (~> 10.0)
|
|
68
|
+
rspec
|
|
69
|
+
tp-cli!
|
|
70
|
+
|
|
71
|
+
BUNDLED WITH
|
|
72
|
+
1.10.6
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015 Evan Dorn, Anne Vetto
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# tp-cli
|
|
2
|
+
CLI tool for submitting activity information to [TimePulse](https://github.com/TimePulse/TimePulse)
|
|
3
|
+
|
|
4
|
+
###User Configuration
|
|
5
|
+
Tp-cli relies on YAML files in user and project directories for information about how and where to send information. For user-specific information, we recommend you place a `timepulse.yml` in one of these directories:
|
|
6
|
+
|
|
7
|
+
* ~/.timepulse
|
|
8
|
+
* ~/
|
|
9
|
+
* /usr/share/timepulse
|
|
10
|
+
* /etc/timepulse
|
|
11
|
+
|
|
12
|
+
A user `timepulse.yml` should have the following information:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
timepulse_url: http://[www.timepulse.io]/activities.json
|
|
16
|
+
login: [yourname@emailaddress.com]
|
|
17
|
+
authorization: [insert your API key here]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Your implementation of timepulse may have a different website, but the url should still end with `/activities.json`. You can generate a new API key on your user profile on TimePulse.
|
|
21
|
+
|
|
22
|
+
Individual projects that are billed in TimePulse should also have a `timepulse.yml` file in their root directory, or in a config directory off of root. A project `timepulse.yml` should have the following information:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
project_id: [2]
|
|
26
|
+
directory_name: [Main Project Directory]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The `project_id` is the number used by TimePulse to identify the project billed for its work on a particular project. The `directory_name` line is optional. If you want to specify a more descriptive name for the directory being tracked by `cwd` annotations, you can uncomment this line and specify a new name. Otherwise, the message will include the current working directory.
|
|
30
|
+
|
|
31
|
+
### Sending notes
|
|
32
|
+
The command `tp-cli note "Note message"` can be used to annotate your work without having to visit the TimePulse web interface. If you are currently logged into a project, the note will automatically be added to your current work unit. Otherwise, it will be saved so you can use it to catch unbilled time.
|
|
33
|
+
|
|
34
|
+
### Using direnv and cwd
|
|
35
|
+
The `tp-cli cwd` command is designed to be used in conjunction with [direnv](http://direnv.net/). By adding `tp-cli cwd` to a project directory's `.envrc` file, you will automatically send an annotation to TimePulse. You can use these notes to ensure that you don't lose any time working on a project.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# vim: set ft=ruby :
|
|
2
|
+
require 'corundum/tasklibs'
|
|
3
|
+
|
|
4
|
+
# This Rakefile makes use of the Corundum tasklibs to parameterize lots and
|
|
5
|
+
# lots of tasks to build your gem. Most of this is (minimal) boilerplate, but
|
|
6
|
+
# there are some places where you can configure exactly how the tasks should
|
|
7
|
+
# work.
|
|
8
|
+
#
|
|
9
|
+
# If you haven't seen the pattern before, simply instantiating the tasklib
|
|
10
|
+
# class (i.e. SomeTasklib.new) is enough to create all the tasks it's
|
|
11
|
+
# responsible for. If you do need to configure a tasklib, you can give ::new a
|
|
12
|
+
# block which will receive the tasklib to configure. c.f. QuestionableContent
|
|
13
|
+
# for an example.
|
|
14
|
+
#
|
|
15
|
+
# (Further docs for all the Corundum tasklibs will be coming to an Internet
|
|
16
|
+
# near you real soon now.)
|
|
17
|
+
module Corundum
|
|
18
|
+
Corundum::register_project(__FILE__)
|
|
19
|
+
|
|
20
|
+
# The Core tasklib coordinates the other tasks. Generally it doesn't need any
|
|
21
|
+
# configuration.
|
|
22
|
+
core = Core.new
|
|
23
|
+
|
|
24
|
+
core.in_namespace do
|
|
25
|
+
# The GemspecFiles tasklib is responsible for checking that all the files
|
|
26
|
+
# necessary for your gem are listed in the Gemfile. Usually you don't need
|
|
27
|
+
# to add any configuration. Of note is the "extra_files" configuration - a
|
|
28
|
+
# list of files that need to be included but that Corundum might not be
|
|
29
|
+
# able to detect on its own.
|
|
30
|
+
GemspecFiles.new(core)
|
|
31
|
+
|
|
32
|
+
# QuestionableContent searches codefiles for words (especially in comments)
|
|
33
|
+
# that you might not want going out into the world. Note that QC is added 4
|
|
34
|
+
# times by default with different types of text.
|
|
35
|
+
#
|
|
36
|
+
# If QC is wrong about something (e.g. there's a completely legitimate
|
|
37
|
+
# reason that 'p' appears on a line) You can tag the line with an '#ok'
|
|
38
|
+
# comment to have QC ignore it.
|
|
39
|
+
|
|
40
|
+
# This default checks for unacceptable language (of both the profanity
|
|
41
|
+
# and -ism varieties) before release, as well as debugging statements
|
|
42
|
+
# like debugger, byebug, puts, p, etc. accidentally left in the code.
|
|
43
|
+
#
|
|
44
|
+
# Also available: 'unfinished': TODO and XXX
|
|
45
|
+
["debug", "profanity", "ableism", "racism"].each do |type|
|
|
46
|
+
QuestionableContent.new(core) do |content|
|
|
47
|
+
content.type = type
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Corundum won't let you release a gem where any tests fail. By default, it
|
|
52
|
+
# assumes RSpec is used to test the project (alternative implementations
|
|
53
|
+
# are anxiously encouraged!)
|
|
54
|
+
rspec = RSpec.new(core)
|
|
55
|
+
|
|
56
|
+
# To make sure that tests don't just pass because they're incomplete,
|
|
57
|
+
# Corundum also requires a coverage threshold, which we measure with
|
|
58
|
+
# Simplecov. Coverage also figures into how we determine that files should
|
|
59
|
+
# be in the gemspec (covered files should be included, and included files
|
|
60
|
+
# should be covered)
|
|
61
|
+
SimpleCov.new(core, rspec) do |cov|
|
|
62
|
+
cov.threshold = 85
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# The tasks to actually take code + gemspec and package into a gem. All its
|
|
66
|
+
# configuration should be determined by the gemspec itself.
|
|
67
|
+
gem = GemBuilding.new(core)
|
|
68
|
+
|
|
69
|
+
# Tasks for uploading gems to rubygems.com - called GemCutter for
|
|
70
|
+
# historical reasons.
|
|
71
|
+
GemCutter.new(core,gem)
|
|
72
|
+
|
|
73
|
+
# We require that the code for a gem be pushed before releasing, and tag
|
|
74
|
+
# the branch with the version of the gem automatically. Corundum assumes
|
|
75
|
+
# Git for version control - alternatives encouraged.
|
|
76
|
+
Git.new(core) do |vc|
|
|
77
|
+
vc.branch = "master"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
task :default => [:release]
|
data/bin/tp-cli
ADDED
data/lib/config.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'valise'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
|
|
4
|
+
module TpCommandLine
|
|
5
|
+
class Config
|
|
6
|
+
def file_set
|
|
7
|
+
Valise::Set.define do
|
|
8
|
+
ro "."
|
|
9
|
+
ro "config/"
|
|
10
|
+
ro "~/.timepulse"
|
|
11
|
+
ro "~/"
|
|
12
|
+
ro "/usr/share/timepulse"
|
|
13
|
+
ro "/etc/timepulse"
|
|
14
|
+
|
|
15
|
+
handle "*.yml", :yaml, :hash_merge
|
|
16
|
+
handle "*.yaml", :yaml, :hash_merge
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def load_config
|
|
21
|
+
@config_hash = file_set.contents("timepulse.yml")
|
|
22
|
+
|
|
23
|
+
missing_fields = ['timepulse_url', 'project_id', 'login',
|
|
24
|
+
'authorization'].find_all {|k| !@config_hash.keys.include? k}
|
|
25
|
+
unless missing_fields.empty?
|
|
26
|
+
puts "Missing necessary parameter/s: #{missing_fields.join(", ")}"
|
|
27
|
+
exit
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
return @config_hash
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/tp_cli.rb
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'typhoeus'
|
|
2
|
+
require 'config'
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module TpCommandLine
|
|
6
|
+
class ActivityTrack
|
|
7
|
+
|
|
8
|
+
attr_reader :request
|
|
9
|
+
|
|
10
|
+
def initialize(args)
|
|
11
|
+
@config_data = TpCommandLine::Config.new.load_config
|
|
12
|
+
description = determine_description(args)
|
|
13
|
+
@server_url = @config_data["timepulse_url"]
|
|
14
|
+
@request_options = {
|
|
15
|
+
method: :post,
|
|
16
|
+
body: JSON.dump({
|
|
17
|
+
activity: {
|
|
18
|
+
description: description,
|
|
19
|
+
project_id: @config_data['project_id'],
|
|
20
|
+
source: "API",
|
|
21
|
+
time: Time.now.utc
|
|
22
|
+
}
|
|
23
|
+
}),
|
|
24
|
+
headers: {
|
|
25
|
+
login: @config_data['login'],
|
|
26
|
+
Authorization: @config_data['authorization'],
|
|
27
|
+
'Accept-Encoding' => 'application/json',
|
|
28
|
+
'Content-Type' => 'application/json'
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
#determine user activity and user feedback or what to POST
|
|
34
|
+
def determine_description(args)
|
|
35
|
+
if args[0] == "note" && args[1].is_a?(String)
|
|
36
|
+
args[1]
|
|
37
|
+
elsif args[0] == "cwd"
|
|
38
|
+
directory = @config_data["directory_name"] || Dir.getwd
|
|
39
|
+
"Changed working directory to #{directory}"
|
|
40
|
+
else
|
|
41
|
+
puts "\nPlease specify action: 'tp-cli note' or 'tp-cli cwd'"
|
|
42
|
+
exit
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def send_to_timepulse
|
|
47
|
+
@request = Typhoeus::Request.new(@server_url, @request_options)
|
|
48
|
+
|
|
49
|
+
begin
|
|
50
|
+
@request.run
|
|
51
|
+
rescue StandardError => err
|
|
52
|
+
puts "\n Please check your internet connection and that the project site is not currently offline."
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
handle_response(@request.response)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def handle_response(response)
|
|
59
|
+
case response.response_code
|
|
60
|
+
when 201
|
|
61
|
+
puts "\nThe activity was sent to TimePulse."
|
|
62
|
+
when 401
|
|
63
|
+
puts "\nThe TimePulse server was unable to authorize you. Check the API token in your timepulse.yml files."
|
|
64
|
+
when 422
|
|
65
|
+
puts "\nThere was an error saving to TimePulse. Please check the information in your timepulse.yml files."
|
|
66
|
+
if response.body
|
|
67
|
+
puts "Rails Errors:"
|
|
68
|
+
errors = JSON.parse(response.body)
|
|
69
|
+
errors.each { |k, v| v.each { |vsub| puts "#{k} #{vsub}"}}
|
|
70
|
+
end
|
|
71
|
+
when 500
|
|
72
|
+
puts "\nThere was an internal server error while handling your request. Tell your TimePulse administrator to check their logs."
|
|
73
|
+
when 0
|
|
74
|
+
puts "\nPlease check your internet connection and that the project site is not currently offline.\nCurl Error: #{response.return_code}"
|
|
75
|
+
else
|
|
76
|
+
puts "\nTimePulse returned an unexpected response: #{response.response_code}"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/tp_cli_spec.rb
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe TpCommandLine::ActivityTrack do
|
|
4
|
+
|
|
5
|
+
describe '#determine_description' do
|
|
6
|
+
|
|
7
|
+
let :activity_track do
|
|
8
|
+
TpCommandLine::ActivityTrack.new(args)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
context "when given no arguments" do
|
|
12
|
+
let :args do
|
|
13
|
+
[]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "prints a message and exits" do
|
|
17
|
+
expect do
|
|
18
|
+
expect do
|
|
19
|
+
activity_track.determine_description(args)
|
|
20
|
+
end.to output("\nPlease specify action: 'tp-cli note' or 'tp-cli cwd'\n").to_stdout
|
|
21
|
+
end.to raise_error(SystemExit)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context "when given the 'note' argument" do
|
|
26
|
+
let :args do
|
|
27
|
+
["note", "Foo"]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "returns second argument" do
|
|
31
|
+
expect(activity_track.determine_description(args)).
|
|
32
|
+
to eq("Foo")
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context "when given the 'cwd' argument" do
|
|
37
|
+
let :args do
|
|
38
|
+
["cwd"]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context "with no working_directory in config" do
|
|
42
|
+
it "sends the current working directory to the server" do
|
|
43
|
+
allow(Dir).to receive(:getwd).and_return("mock_directory")
|
|
44
|
+
|
|
45
|
+
expect(activity_track.determine_description(args)).
|
|
46
|
+
to eq("Changed working directory to mock_directory")
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context "with no working_directory in config" do
|
|
51
|
+
|
|
52
|
+
it "sends the config message to the server" do
|
|
53
|
+
activity_track.instance_variable_set(:@config_data,
|
|
54
|
+
{"directory_name" => "mock_directory"}
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
expect(activity_track.determine_description(args)).
|
|
58
|
+
to eq("Changed working directory to mock_directory")
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context "when given other arguments" do
|
|
65
|
+
let :args do
|
|
66
|
+
["Bar", "Foo", "OMG", "SO", "MANY", "ARGS"]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "prints a message and exits" do
|
|
70
|
+
expect do
|
|
71
|
+
expect do
|
|
72
|
+
activity_track.determine_description(args)
|
|
73
|
+
end.to output("\nPlease specify action: 'tp-cli note' or 'tp-cli cwd'\n").to_stdout
|
|
74
|
+
end.to raise_error(SystemExit)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
describe "#send_to_timepulse" do
|
|
80
|
+
let :config_data do
|
|
81
|
+
{
|
|
82
|
+
"timepulse_url" => "www.timepulse.io/activities",
|
|
83
|
+
"project_id" => "2",
|
|
84
|
+
"login" => "Logan Loggins",
|
|
85
|
+
"authorization" => "AuthorizationToTheDangerZone"
|
|
86
|
+
}
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
let :activity_track do
|
|
90
|
+
TpCommandLine::ActivityTrack.new(["note", "Everybody cut footloose!"])
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
before :each do
|
|
94
|
+
config_double = double("TpCommandLine::Config")
|
|
95
|
+
allow(config_double).to receive(:load_config).and_return(config_data)
|
|
96
|
+
allow(TpCommandLine::Config).to receive(:new).and_return(config_double)
|
|
97
|
+
|
|
98
|
+
Typhoeus.stub(/timepulse.io/).and_return(response)
|
|
99
|
+
|
|
100
|
+
@original_stdout = $stdout
|
|
101
|
+
$stdout = File.open(File::NULL, "w")
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
after :each do
|
|
105
|
+
$stdout = @original_stdout
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
context "with valid data" do
|
|
109
|
+
let :response do
|
|
110
|
+
Typhoeus::Response.new(response_code: 201)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "assigns the correct url to the request" do
|
|
114
|
+
activity_track.send_to_timepulse
|
|
115
|
+
|
|
116
|
+
expect(activity_track.request.base_url).to eq("www.timepulse.io/activities")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "assigns the correct options to the request" do
|
|
120
|
+
activity_track.send_to_timepulse
|
|
121
|
+
options = activity_track.request.original_options
|
|
122
|
+
activity_params = JSON.parse(options[:body])
|
|
123
|
+
headers = options[:headers]
|
|
124
|
+
|
|
125
|
+
expect(options[:method]).to eq(:post)
|
|
126
|
+
expect(activity_params["activity"]["description"]).to eq("Everybody cut footloose!")
|
|
127
|
+
expect(activity_params["activity"]["project_id"]).to eq("2")
|
|
128
|
+
expect(activity_params["activity"]["source"]).to eq("API")
|
|
129
|
+
expect(headers[:login]).to eq("Logan Loggins")
|
|
130
|
+
expect(headers[:Authorization]).to eq("AuthorizationToTheDangerZone")
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it "receives a successful response" do
|
|
134
|
+
activity_track.send_to_timepulse
|
|
135
|
+
expect(activity_track.request.response).not_to be_nil
|
|
136
|
+
expect(activity_track.request.response.response_code).to eq(201)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "calls handle_response" do
|
|
140
|
+
expect(activity_track).to receive(:handle_response).and_call_original
|
|
141
|
+
activity_track.send_to_timepulse
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
describe "#handle_response" do
|
|
147
|
+
let :activity_track do
|
|
148
|
+
TpCommandLine::ActivityTrack.new(['cwd'])
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
context "with a 201 response code (success)" do
|
|
152
|
+
let :response do
|
|
153
|
+
dbl = double
|
|
154
|
+
allow(dbl).to receive(:response_code).and_return(201)
|
|
155
|
+
dbl
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it "prints a successful response" do
|
|
159
|
+
expect do
|
|
160
|
+
activity_track.handle_response(response)
|
|
161
|
+
end.to output("\nThe activity was sent to TimePulse.\n").to_stdout
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
context "with a 401 response code (unauthorized)" do
|
|
166
|
+
let :response do
|
|
167
|
+
dbl = double
|
|
168
|
+
allow(dbl).to receive(:response_code).and_return(401)
|
|
169
|
+
dbl
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "prints a notification of error" do
|
|
173
|
+
expect do
|
|
174
|
+
activity_track.handle_response(response)
|
|
175
|
+
end.to output("\nThe TimePulse server was unable to authorize you. Check the API token in your timepulse.yml files.\n").to_stdout
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
context "with a 422 response code (could not save)" do
|
|
180
|
+
let :response do
|
|
181
|
+
dbl = double
|
|
182
|
+
allow(dbl).to receive(:response_code).and_return(422)
|
|
183
|
+
allow(dbl).to receive(:body).and_return(body)
|
|
184
|
+
dbl
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
context "and no errors in body" do
|
|
188
|
+
let :body do
|
|
189
|
+
nil
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
it "prints a notification of error" do
|
|
193
|
+
expect do
|
|
194
|
+
activity_track.handle_response(response)
|
|
195
|
+
end.to output("\nThere was an error saving to TimePulse. Please check the information in your timepulse.yml files.\n").to_stdout
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
context "with errors in body" do
|
|
200
|
+
let :body do
|
|
201
|
+
'{"field": ["error message"]}'
|
|
202
|
+
end
|
|
203
|
+
it "prints a notification of error" do
|
|
204
|
+
expect do
|
|
205
|
+
activity_track.handle_response(response)
|
|
206
|
+
end.to output("\nThere was an error saving to TimePulse. Please check the information in your timepulse.yml files.\nRails Errors:\nfield error message\n").to_stdout
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
context "with a 500 response code (internal server error)" do
|
|
212
|
+
let :response do
|
|
213
|
+
dbl = double
|
|
214
|
+
allow(dbl).to receive(:response_code).and_return(500)
|
|
215
|
+
dbl
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
it "prints a notification of error" do
|
|
219
|
+
expect do
|
|
220
|
+
activity_track.handle_response(response)
|
|
221
|
+
end.to output("\nThere was an internal server error while handling your request. Tell your TimePulse administrator to check their logs.\n").to_stdout
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
context "with a 0 response code (server connectivity issues)" do
|
|
226
|
+
let :response do
|
|
227
|
+
dbl = double
|
|
228
|
+
allow(dbl).to receive(:response_code).and_return(0)
|
|
229
|
+
allow(dbl).to receive(:return_code).and_return("foo")
|
|
230
|
+
dbl
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
it "prints a notification of error" do
|
|
234
|
+
expect do
|
|
235
|
+
activity_track.handle_response(response)
|
|
236
|
+
end.to output("\nPlease check your internet connection and that the project site is not currently offline.\nCurl Error: foo\n").to_stdout
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
context "with an unexpected response code" do
|
|
241
|
+
let :response do
|
|
242
|
+
dbl = double
|
|
243
|
+
allow(dbl).to receive(:response_code).and_return(418)
|
|
244
|
+
dbl
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
it "prints a notification of error" do
|
|
248
|
+
expect do
|
|
249
|
+
activity_track.handle_response(response)
|
|
250
|
+
end.to output("\nTimePulse returned an unexpected response: 418\n").to_stdout
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end
|
data/tp-cli.gemspec
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Gem::Specification.new do |spec|
|
|
2
|
+
spec.name = "tp-cli"
|
|
3
|
+
#{MAJOR: incompatible}.{MINOR added feature}.{PATCH bugfix}-{LABEL}
|
|
4
|
+
spec.version = "0.0.1"
|
|
5
|
+
author_list = {
|
|
6
|
+
"Anne Vetto" => "anne@lrdesign.com",
|
|
7
|
+
"Tony Delgado-Willis" => "tonydw@lrdesign.com",
|
|
8
|
+
"Evan Dorn" => "evan@lrdesign.com"
|
|
9
|
+
}
|
|
10
|
+
spec.authors = author_list.keys
|
|
11
|
+
spec.email = spec.authors.map {|name| author_list[name]}
|
|
12
|
+
spec.summary = "Timepulse Command Line Interface"
|
|
13
|
+
spec.description = <<-EndDescription
|
|
14
|
+
CLI tool for submitting activity information to Timepulse
|
|
15
|
+
EndDescription
|
|
16
|
+
|
|
17
|
+
spec.rubyforge_project= spec.name.downcase
|
|
18
|
+
spec.homepage = "https://github.com/TimePulse/tp-cli"
|
|
19
|
+
spec.required_rubygems_version = Gem::Requirement.new(">= 0") if spec.respond_to? :required_rubygems_version=
|
|
20
|
+
|
|
21
|
+
# Do this: y$@"
|
|
22
|
+
# !!find lib bin doc spec spec_help -not -regex '.*\.sw.' -type f 2>/dev/null
|
|
23
|
+
spec.files = %w[ .envrc.example .gitignore Gemfile Gemfile.lock LICENSE.txt README.md Rakefile bin/tp-cli lib/tp_cli.rb lib/config.rb spec/spec_helper.rb spec/tp_cli_spec.rb tp-cli.gemspec]
|
|
24
|
+
|
|
25
|
+
# spec.test_file = "spec_help/gem_test_suite.rb"
|
|
26
|
+
spec.licenses = ["MIT"]
|
|
27
|
+
spec.require_paths = %w[lib/]
|
|
28
|
+
spec.rubygems_version = "1.3.5"
|
|
29
|
+
|
|
30
|
+
spec.has_rdoc = true
|
|
31
|
+
spec.extra_rdoc_files = Dir.glob("doc/**/*")
|
|
32
|
+
spec.rdoc_options = %w{--inline-source }
|
|
33
|
+
spec.rdoc_options += %w{--main doc/README }
|
|
34
|
+
spec.rdoc_options += ["--title", "#{spec.name}-#{spec.version} Documentation"]
|
|
35
|
+
|
|
36
|
+
#spec.add_dependency("", "> 0")
|
|
37
|
+
spec.add_dependency 'typhoeus', '~> 0.8'
|
|
38
|
+
spec.add_dependency 'valise', '~> 1.1'
|
|
39
|
+
|
|
40
|
+
#spec.post_install_message = "Thanks for installing my gem!"
|
|
41
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: tp-cli
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Anne Vetto
|
|
8
|
+
- Tony Delgado-Willis
|
|
9
|
+
- Evan Dorn
|
|
10
|
+
autorequire:
|
|
11
|
+
bindir: bin
|
|
12
|
+
cert_chain: []
|
|
13
|
+
date: 2015-11-19 00:00:00.000000000 Z
|
|
14
|
+
dependencies:
|
|
15
|
+
- !ruby/object:Gem::Dependency
|
|
16
|
+
name: typhoeus
|
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
|
18
|
+
requirements:
|
|
19
|
+
- - "~>"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0.8'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - "~>"
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '0.8'
|
|
29
|
+
- !ruby/object:Gem::Dependency
|
|
30
|
+
name: valise
|
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
|
32
|
+
requirements:
|
|
33
|
+
- - "~>"
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: '1.1'
|
|
36
|
+
type: :runtime
|
|
37
|
+
prerelease: false
|
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
- - "~>"
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: '1.1'
|
|
43
|
+
description: |2
|
|
44
|
+
CLI tool for submitting activity information to Timepulse
|
|
45
|
+
email:
|
|
46
|
+
- anne@lrdesign.com
|
|
47
|
+
- tonydw@lrdesign.com
|
|
48
|
+
- evan@lrdesign.com
|
|
49
|
+
executables: []
|
|
50
|
+
extensions: []
|
|
51
|
+
extra_rdoc_files: []
|
|
52
|
+
files:
|
|
53
|
+
- ".envrc.example"
|
|
54
|
+
- ".gitignore"
|
|
55
|
+
- Gemfile
|
|
56
|
+
- Gemfile.lock
|
|
57
|
+
- LICENSE.txt
|
|
58
|
+
- README.md
|
|
59
|
+
- Rakefile
|
|
60
|
+
- bin/tp-cli
|
|
61
|
+
- lib/config.rb
|
|
62
|
+
- lib/tp_cli.rb
|
|
63
|
+
- spec/spec_helper.rb
|
|
64
|
+
- spec/tp_cli_spec.rb
|
|
65
|
+
- tp-cli.gemspec
|
|
66
|
+
homepage: https://github.com/TimePulse/tp-cli
|
|
67
|
+
licenses:
|
|
68
|
+
- MIT
|
|
69
|
+
metadata: {}
|
|
70
|
+
post_install_message:
|
|
71
|
+
rdoc_options:
|
|
72
|
+
- "--inline-source"
|
|
73
|
+
- "--main"
|
|
74
|
+
- doc/README
|
|
75
|
+
- "--title"
|
|
76
|
+
- tp-cli-0.0.1 Documentation
|
|
77
|
+
require_paths:
|
|
78
|
+
- lib/
|
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
80
|
+
requirements:
|
|
81
|
+
- - ">="
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: '0'
|
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
89
|
+
requirements: []
|
|
90
|
+
rubyforge_project: tp-cli
|
|
91
|
+
rubygems_version: 2.4.8
|
|
92
|
+
signing_key:
|
|
93
|
+
specification_version: 4
|
|
94
|
+
summary: Timepulse Command Line Interface
|
|
95
|
+
test_files: []
|