hammerhead 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +14 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/LICENSE.txt +20 -0
- data/README.md +207 -0
- data/exe/hammerhead +18 -0
- data/lib/hammerhead.rb +50 -0
- data/lib/hammerhead/cli.rb +74 -0
- data/lib/hammerhead/command.rb +118 -0
- data/lib/hammerhead/commands/clients.rb +58 -0
- data/lib/hammerhead/commands/status.rb +154 -0
- data/lib/hammerhead/configuration.rb +131 -0
- data/lib/hammerhead/utils.rb +22 -0
- data/lib/hammerhead/version.rb +4 -0
- data/lib/harvest.rb +17 -0
- data/lib/harvest/connection.rb +117 -0
- data/lib/tasks/hammerhead.rake +25 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 14377ccc5ecea39d948921b57b2dbaa0ba3587a3358dd8b157cb1ea62c065903
|
4
|
+
data.tar.gz: 0715f4dfd5fcd3c05dca7f465aaa3786c063962678d6908689e333acee53bb5a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8d10e94d35cb84c1b49a798c53a83f7a18569e23cef1fbfdb459225469594828c851dcaaeab45a8aef959847c6e261397a0591dc858c991883c407fbeed150b0
|
7
|
+
data.tar.gz: 7c9f0718653bcf825ac604bb24ac1d3bb827c544a3cd9fc201ab05fa140c1cd78117f1b873f68db9c65d7e80d2b2011086727d519a855973483b2c4e77bba7d4
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Hammerhead Changes
|
2
|
+
|
3
|
+
## 0.1.0 (Initial Release)
|
4
|
+
|
5
|
+
### Released on [Date]
|
6
|
+
|
7
|
+
* Uses TTY Toolkit
|
8
|
+
* Calls Harvest v1 API via 'harvested'
|
9
|
+
* Returns list of 'active' clients by default
|
10
|
+
* Returns all clients
|
11
|
+
* Generates weekly status report for specified client
|
12
|
+
* Supports client 'nicknames'
|
13
|
+
* Supports client exclusions
|
14
|
+
* Supports rudimentary configuration file
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at mel@juicyparts.com. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [https://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: https://contributor-covenant.org
|
74
|
+
[version]: https://contributor-covenant.org/version/1/4/
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Juicy Parts Software, LLC
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
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, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,207 @@
|
|
1
|
+
# Hammerhead
|
2
|
+
|
3
|
+
A tool to generate status reports from your Harvest timesheet.
|
4
|
+
|
5
|
+
With this tool you can produce client-specific status reports from the entries you make in your Harvest timesheet.
|
6
|
+
|
7
|
+
## Motivation
|
8
|
+
|
9
|
+
That's the reason I created this tool: I produce weekly status reports for my clients. This is the first iteration, and because of this, it is tailored to my needs.
|
10
|
+
|
11
|
+
At the end of this document I'll document the road map I have for this tool. Stay tuned.
|
12
|
+
|
13
|
+
## Notable Components
|
14
|
+
|
15
|
+
### Harvest
|
16
|
+
|
17
|
+
You need a [Harvest](https://www.getharvest.com/) account, because this information is used to authenticate this tool against the Harvest V1 API.
|
18
|
+
|
19
|
+
**WARNING**: According to the [API V1 Documentation](https://help.getharvest.com/api-v1/), this API is deprecated but will still be available for 'legacy' applications. Upgrading to use Harvest V2 API is already in the Road Map. However, until then, I'm making note that I'm using the [harvested](https://rubygems.org/gems/harvested) gem to provide API access to the Harvest information.
|
20
|
+
|
21
|
+
In a configuration file (`'hammerhead.yml'`) you will specify:
|
22
|
+
|
23
|
+
```
|
24
|
+
subdomain: - Your Harvest subdomain
|
25
|
+
username: - Your Harvest username
|
26
|
+
password: - Your Harvest password
|
27
|
+
```
|
28
|
+
|
29
|
+
**NOTE**: This tool uses the Optional Project Code when displaying status reports.
|
30
|
+
|
31
|
+
### TTY Toolkit
|
32
|
+
|
33
|
+
[TTY Toolkit](https://ttytoolkit.org/) provides the skeleton around which Hammerhead is built. It's a wonderfully easy toolkit to use. I'm barely scratching the surface of its capabilities.
|
34
|
+
|
35
|
+
**WARNING**: As of version `'0.10.0'` there is a dependency on an old version of Bundler. Bundler version `1.17.3` works fine. I bring this up because you will receive warnings/errors when trying to use newer versions. When `tty` upgrades I will update this tool. Until then run bundler like so:
|
36
|
+
|
37
|
+
```sh
|
38
|
+
$ bundle _1.17.3_ <command>
|
39
|
+
```
|
40
|
+
|
41
|
+
Because of this specific dependency on `bundler` through `tty` I have elected to replicate the dependecy requirement in Hammerhead's gemspec.
|
42
|
+
|
43
|
+
## Installation
|
44
|
+
|
45
|
+
Add this line to your application's Gemfile:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
gem 'hammerhead'
|
49
|
+
```
|
50
|
+
|
51
|
+
And then execute:
|
52
|
+
|
53
|
+
$ bundle install
|
54
|
+
|
55
|
+
Or install it yourself as:
|
56
|
+
|
57
|
+
$ gem install hammerhead
|
58
|
+
|
59
|
+
## Usage
|
60
|
+
|
61
|
+
### Commands
|
62
|
+
|
63
|
+
#### `clients`
|
64
|
+
|
65
|
+
Use this command to obtain a list of your clients. The default behavior is to return 'active' clients.
|
66
|
+
|
67
|
+
```
|
68
|
+
Usage:
|
69
|
+
hammerhead clients [OPTIONS]
|
70
|
+
|
71
|
+
Options:
|
72
|
+
-a, [--all], [--no-all] # Return all clients from Harvest
|
73
|
+
-h, [--help], [--no-help] # Display usage information
|
74
|
+
|
75
|
+
Description:
|
76
|
+
Fetch list of clients from Harvest.
|
77
|
+
|
78
|
+
The default behavior is to return 'active' clients, only.
|
79
|
+
|
80
|
+
Add the --all flag to return entire list of clients.
|
81
|
+
```
|
82
|
+
|
83
|
+
Displayed in the console will be a table of your clients. The first column will be their numeric id; this is assigned by Harvest. The second column will be the name you assigned to them. The `status` command, in its current form, requires the numeric id to be specified.
|
84
|
+
|
85
|
+
#### `status CLIENT`
|
86
|
+
|
87
|
+
Use this command to obtain a status report for the specified client.
|
88
|
+
|
89
|
+
```
|
90
|
+
Usage:
|
91
|
+
hammerhead status [OPTIONS] CLIENT
|
92
|
+
|
93
|
+
Options:
|
94
|
+
-s, [--short-cut], [--no-short-cut] # CLIENT value is a user-defined short-cut
|
95
|
+
[--start-date=YYYY-MM-DD] # Start date of timesheet query
|
96
|
+
[--end-date=YYYY-MM-DD] # End date of timesheet query
|
97
|
+
-h, [--help], [--no-help] # Display usage information
|
98
|
+
|
99
|
+
Description:
|
100
|
+
Generate status report for specified client.
|
101
|
+
|
102
|
+
The default behavior is to query up to a week's worth of timesheet entries for
|
103
|
+
the specififed CLIENT.
|
104
|
+
|
105
|
+
CLIENT can either be the Id or Name of one of your Harvest Clients. Obtain this
|
106
|
+
information with the 'clients' command.
|
107
|
+
|
108
|
+
It can also be a user-defined shortcut. Please see the README for details on
|
109
|
+
creating shortcuts. However when used, you must pass the --short-cut flag.
|
110
|
+
|
111
|
+
Start and end dates are automatically calculated. They are based on _your_ 'Start
|
112
|
+
Week On' Setting.
|
113
|
+
|
114
|
+
You can alter this behavior by specifying --start-date or --end-date.
|
115
|
+
|
116
|
+
Constraints when specifying dates:
|
117
|
+
|
118
|
+
- start-date must occur before end-date
|
119
|
+
|
120
|
+
- start-date and end-date must be at least 1 day apart
|
121
|
+
|
122
|
+
- both are optional
|
123
|
+
|
124
|
+
- specifying start-date causes end-date to equal "tomorrow"
|
125
|
+
|
126
|
+
- specifying end-date requies the presense of start-date
|
127
|
+
```
|
128
|
+
|
129
|
+
**WARNING**: The `--start-date` and `--end-date` flags are currently not supported. Supporting them is already on the Road Map.
|
130
|
+
|
131
|
+
This is the heart of the Hammerhead tool. When passed the numeric id of a client, this command attempts to grab timesheet entries for active projects for the specified client. If there are no timesheet entries, or active projects, this command responds with an appropriate message in the console.
|
132
|
+
|
133
|
+
If you work on multiple projects for a client, the output will be grouped by project, by timesheet entry.
|
134
|
+
|
135
|
+
Again, this version is tailored to my needs and, as such, is a tiny bit complicated. My business weeks run from Monday to Sunday, therefore this tool attempts to figure out the start-date and end-date based on 'Today'. If 'Today' is Monday, a report for the previous Monday to Sunday is generated, otherwise a report from Monday to 'Today' is generated.
|
136
|
+
|
137
|
+
##### Client Name Shortcuts
|
138
|
+
|
139
|
+
These nicknames, or client name snippets, can be configured in `'hammerhead.yml'`. In lieu of Client Name support you can use this to setup shortcuts for report generation.
|
140
|
+
|
141
|
+
```sh
|
142
|
+
$ hammerhead status -s <nickname>
|
143
|
+
```
|
144
|
+
|
145
|
+
### Configuration
|
146
|
+
|
147
|
+
Hammerhead requires the presense of a configuration file named: `'hammerhead.yml'`. The tool will search the directory in which the command is executed and in your home directory. An error will be displayed when the file can not be located.
|
148
|
+
|
149
|
+
#### Sample Configuration File
|
150
|
+
|
151
|
+
```yaml
|
152
|
+
# REQUIRED
|
153
|
+
harvest:
|
154
|
+
subdomain: SET_ME
|
155
|
+
username: SET_ME
|
156
|
+
password: SET_ME
|
157
|
+
|
158
|
+
# OPTIONAL
|
159
|
+
clients:
|
160
|
+
exclude:
|
161
|
+
- <client id>
|
162
|
+
shortcuts:
|
163
|
+
<nickname>:
|
164
|
+
id: <client id>
|
165
|
+
name: <client name>
|
166
|
+
```
|
167
|
+
|
168
|
+
Because of the `harvested` gem, and its use of Basic Authentication, you need to specify your credentials in order for the tool to authenticate itself against the Harvest V1 API. **GUARD YOUR CREDENTIALS!**
|
169
|
+
|
170
|
+
There are some optional configuration items that may prove useful to you. If you have a client, for whatever reason, you wish to exclude from any and all client listings, add their Client Id to the list that is `clients.exclude`. Additionally, if you'd like an easy-to-remember nickname for one, or more, of your clients, you can define them until `clients.shortcuts`. For example:
|
171
|
+
|
172
|
+
```yaml
|
173
|
+
clients:
|
174
|
+
shortcuts:
|
175
|
+
acme:
|
176
|
+
id: 999999999
|
177
|
+
name: ACME Co, Inc
|
178
|
+
```
|
179
|
+
```sh
|
180
|
+
$ hammerhead status -s acme
|
181
|
+
```
|
182
|
+
|
183
|
+
## Development
|
184
|
+
|
185
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
186
|
+
|
187
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
188
|
+
|
189
|
+
### Road Map
|
190
|
+
|
191
|
+
* Support date range for `status` command
|
192
|
+
* Add template support
|
193
|
+
* Email status report
|
194
|
+
* Use Harvest V2 API
|
195
|
+
|
196
|
+
## Contributing
|
197
|
+
|
198
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/juicyparts/hammerhead. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/juicyparts/hammerhead/blob/master/CODE_OF_CONDUCT.md).
|
199
|
+
|
200
|
+
|
201
|
+
## Code of Conduct
|
202
|
+
|
203
|
+
Everyone interacting in the Hammerhead project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/juicyparts/hammerhead/blob/master/CODE_OF_CONDUCT.md).
|
204
|
+
|
205
|
+
## Copyright
|
206
|
+
|
207
|
+
Copyright (c) 2020 Juicy Parts Software, LLC. See [MIT License](LICENSE.txt) for further details.
|
data/exe/hammerhead
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
lib_path = File.expand_path('../lib', __dir__)
|
5
|
+
$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
|
6
|
+
require 'hammerhead/cli'
|
7
|
+
|
8
|
+
Signal.trap('INT') do
|
9
|
+
warn("\n#{caller.join("\n")}: interrupted")
|
10
|
+
exit(1)
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
Hammerhead::CLI.start
|
15
|
+
rescue Hammerhead::CLI::Error => err
|
16
|
+
puts "ERROR: #{err.message}"
|
17
|
+
exit 1
|
18
|
+
end
|
data/lib/hammerhead.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'hammerhead'
|
3
|
+
require 'hammerhead/configuration'
|
4
|
+
require 'hammerhead/utils'
|
5
|
+
require 'hammerhead/version'
|
6
|
+
|
7
|
+
require 'harvest'
|
8
|
+
|
9
|
+
require 'tty-logger'
|
10
|
+
|
11
|
+
require 'pry-byebug'
|
12
|
+
require 'ap'
|
13
|
+
|
14
|
+
##
|
15
|
+
# Wraps the functionality of the hammerhead tool. Contains the commands
|
16
|
+
# defined, and implemented, by the +tty+ gem.
|
17
|
+
#
|
18
|
+
module Hammerhead
|
19
|
+
##
|
20
|
+
# Commands generated by the +tty+ gem are organized in this module.
|
21
|
+
#
|
22
|
+
module Commands; end
|
23
|
+
|
24
|
+
##
|
25
|
+
# General error used when something bad, or unexpected, occurs.
|
26
|
+
#
|
27
|
+
class Error < StandardError; end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
##
|
31
|
+
# Returns a Hammerhead::Configuration instance
|
32
|
+
#
|
33
|
+
def configuration
|
34
|
+
@configuration ||= Hammerhead::Configuration.new
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Returns a TTY::Logger instance
|
39
|
+
#
|
40
|
+
def logger
|
41
|
+
@logger ||= TTY::Logger.new
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Provides an alternate way to access the +configuration+
|
46
|
+
def configure
|
47
|
+
yield configuration
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
|
5
|
+
module Hammerhead
|
6
|
+
# Handle the application command line parsing
|
7
|
+
# and the dispatch to various command objects
|
8
|
+
#
|
9
|
+
# @api public
|
10
|
+
class CLI < Thor # :nodoc: all
|
11
|
+
# Error raised by this runner
|
12
|
+
Error = Class.new(StandardError)
|
13
|
+
|
14
|
+
desc 'version', 'hammerhead version'
|
15
|
+
def version
|
16
|
+
require_relative 'version'
|
17
|
+
puts "v#{Hammerhead::VERSION} Hammerhead 🦈"
|
18
|
+
end
|
19
|
+
map %w[--version -v] => :version
|
20
|
+
|
21
|
+
desc 'status [OPTIONS] CLIENT', 'Generate status report for specified client'
|
22
|
+
long_desc <<-DESC
|
23
|
+
Generate status report for specified client.
|
24
|
+
|
25
|
+
The default behavior is to query up to a week's worth of timesheet entries for the specififed CLIENT.
|
26
|
+
|
27
|
+
CLIENT can either be the Id or Name of one of your Harvest Clients. Obtain this information with the 'clients' command.
|
28
|
+
|
29
|
+
It can also be a user-defined shortcut. Please see the README for details on creating shortcuts. However when used, you must pass the --short-cut flag.
|
30
|
+
|
31
|
+
Start and end dates are automatically calculated. They are based on _your_ 'Start Week On' Setting.
|
32
|
+
|
33
|
+
You can alter this behavior by specifying --start-date or --end-date.
|
34
|
+
|
35
|
+
Constraints when specifying dates:\n
|
36
|
+
- start-date must occur before end-date\n
|
37
|
+
- start-date and end-date must be at least 1 day apart\n
|
38
|
+
- both are optional\n
|
39
|
+
- specifying start-date causes end-date to equal "tomorrow"\n
|
40
|
+
- specifying end-date requies the presense of start-date
|
41
|
+
DESC
|
42
|
+
method_option :short_cut, aliases: '-s', type: :boolean, desc: 'CLIENT value is a user-defined short-cut'
|
43
|
+
method_option :start_date, banner: 'YYYY-MM-DD', type: :string, desc: 'Start date of timesheet query'
|
44
|
+
method_option :end_date, banner: 'YYYY-MM-DD', type: :string, desc: 'End date of timesheet query'
|
45
|
+
method_option :help, aliases: '-h', type: :boolean, desc: 'Display usage information'
|
46
|
+
def status client
|
47
|
+
if options[:help]
|
48
|
+
invoke :help, ['status']
|
49
|
+
else
|
50
|
+
require_relative 'commands/status'
|
51
|
+
Hammerhead::Commands::Status.new(client, options).execute
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
desc 'clients [OPTIONS]', 'Fetch list of clients from Harvest'
|
56
|
+
long_desc <<-DESC
|
57
|
+
Fetch list of clients from Harvest.
|
58
|
+
|
59
|
+
The default behavior is to return 'active' clients, only.
|
60
|
+
|
61
|
+
Add the --all flag to return entire list of clients.
|
62
|
+
DESC
|
63
|
+
method_option :all, aliases: '-a', type: :boolean, desc: 'Return all clients from Harvest'
|
64
|
+
method_option :help, aliases: '-h', type: :boolean, desc: 'Display usage information'
|
65
|
+
def clients
|
66
|
+
if options[:help]
|
67
|
+
invoke :help, ['clients']
|
68
|
+
else
|
69
|
+
require_relative 'commands/clients'
|
70
|
+
Hammerhead::Commands::Clients.new(options).execute
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module Hammerhead
|
6
|
+
class Command # :nodoc: all
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegators :command, :run
|
10
|
+
|
11
|
+
# Execute this command
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
def execute
|
15
|
+
raise NotImplementedError, "#{self.class}##{__method__} must be implemented"
|
16
|
+
end
|
17
|
+
|
18
|
+
# The external commands runner
|
19
|
+
#
|
20
|
+
# @see http://www.rubydoc.info/gems/tty-command
|
21
|
+
#
|
22
|
+
# @api public
|
23
|
+
def command **options
|
24
|
+
require 'tty-command'
|
25
|
+
TTY::Command.new(options)
|
26
|
+
end
|
27
|
+
|
28
|
+
# The cursor movement
|
29
|
+
#
|
30
|
+
# @see http://www.rubydoc.info/gems/tty-cursor
|
31
|
+
#
|
32
|
+
# @api public
|
33
|
+
def cursor
|
34
|
+
require 'tty-cursor'
|
35
|
+
TTY::Cursor
|
36
|
+
end
|
37
|
+
|
38
|
+
# Open a file or text in the user's preferred editor
|
39
|
+
#
|
40
|
+
# @see http://www.rubydoc.info/gems/tty-editor
|
41
|
+
#
|
42
|
+
# @api public
|
43
|
+
def editor
|
44
|
+
require 'tty-editor'
|
45
|
+
TTY::Editor
|
46
|
+
end
|
47
|
+
|
48
|
+
# File manipulation utility methods
|
49
|
+
#
|
50
|
+
# @see http://www.rubydoc.info/gems/tty-file
|
51
|
+
#
|
52
|
+
# @api public
|
53
|
+
def generator
|
54
|
+
require 'tty-file'
|
55
|
+
TTY::File
|
56
|
+
end
|
57
|
+
|
58
|
+
# Terminal output paging
|
59
|
+
#
|
60
|
+
# @see http://www.rubydoc.info/gems/tty-pager
|
61
|
+
#
|
62
|
+
# @api public
|
63
|
+
def pager **options
|
64
|
+
require 'tty-pager'
|
65
|
+
TTY::Pager.new(options)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Terminal platform and OS properties
|
69
|
+
#
|
70
|
+
# @see http://www.rubydoc.info/gems/tty-pager
|
71
|
+
#
|
72
|
+
# @api public
|
73
|
+
def platform
|
74
|
+
require 'tty-platform'
|
75
|
+
TTY::Platform.new
|
76
|
+
end
|
77
|
+
|
78
|
+
# The interactive prompt
|
79
|
+
#
|
80
|
+
# @see http://www.rubydoc.info/gems/tty-prompt
|
81
|
+
#
|
82
|
+
# @api public
|
83
|
+
def prompt **options
|
84
|
+
require 'tty-prompt'
|
85
|
+
TTY::Prompt.new(options)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Get terminal screen properties
|
89
|
+
#
|
90
|
+
# @see http://www.rubydoc.info/gems/tty-screen
|
91
|
+
#
|
92
|
+
# @api public
|
93
|
+
def screen
|
94
|
+
require 'tty-screen'
|
95
|
+
TTY::Screen
|
96
|
+
end
|
97
|
+
|
98
|
+
# The unix which utility
|
99
|
+
#
|
100
|
+
# @see http://www.rubydoc.info/gems/tty-which
|
101
|
+
#
|
102
|
+
# @api public
|
103
|
+
def which *args
|
104
|
+
require 'tty-which'
|
105
|
+
TTY::Which.which(*args)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Check if executable exists
|
109
|
+
#
|
110
|
+
# @see http://www.rubydoc.info/gems/tty-which
|
111
|
+
#
|
112
|
+
# @api public
|
113
|
+
def exec_exist? *args
|
114
|
+
require 'tty-which'
|
115
|
+
TTY::Which.exist?(*args)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tty-table'
|
4
|
+
require 'hammerhead'
|
5
|
+
require_relative '../command'
|
6
|
+
|
7
|
+
module Hammerhead
|
8
|
+
module Commands
|
9
|
+
##
|
10
|
+
# Implements the +clients+ command.
|
11
|
+
#
|
12
|
+
# This command, using a Harvest.connection, knows how to obtain a list of clients
|
13
|
+
# and display them in a +TTY::Table+. It also outputs the number of clients returned.
|
14
|
+
#
|
15
|
+
# If any errors are caught, they are sent to the Hammerhead.logger.
|
16
|
+
#
|
17
|
+
class Clients < Hammerhead::Command
|
18
|
+
def initialize options # :nodoc:
|
19
|
+
self.options = options
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# :stopdoc:
|
24
|
+
#
|
25
|
+
# TODO: Format Table
|
26
|
+
# TODO: Display different table with '--all'
|
27
|
+
# TODO: Colorize Output
|
28
|
+
def execute input: $stdin, output: $stdout
|
29
|
+
clients = Harvest.connection.clients options
|
30
|
+
|
31
|
+
output.puts "Pass the Id to the 'status' command, or enough of the name to uniquely match."
|
32
|
+
output.puts
|
33
|
+
|
34
|
+
table = TTY::Table.new headers, data(clients)
|
35
|
+
output.puts table.render(:unicode)
|
36
|
+
|
37
|
+
output.puts
|
38
|
+
output.puts "CLIENTS FOUND: #{clients.size}"
|
39
|
+
rescue StandardError => e
|
40
|
+
Hammerhead.logger.error 'CLIENTS COMMAND ERROR:', e
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
attr_accessor :options
|
46
|
+
|
47
|
+
def headers
|
48
|
+
%w[Id Name]
|
49
|
+
end
|
50
|
+
|
51
|
+
def data clients
|
52
|
+
clients.collect do |client|
|
53
|
+
[client.id, client.name]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pry-byebug'
|
4
|
+
|
5
|
+
require 'date'
|
6
|
+
require 'hammerhead'
|
7
|
+
require_relative '../command'
|
8
|
+
|
9
|
+
module Hammerhead
|
10
|
+
module Commands
|
11
|
+
##
|
12
|
+
# Implements the +status+ command.
|
13
|
+
#
|
14
|
+
# Using a Harvest.connection and a client Id, like one obtained via the
|
15
|
+
# +clients+ command, this command prepares a 'status report' for display in
|
16
|
+
# the console.
|
17
|
+
#
|
18
|
+
# This command warns about: an inactive client, a client with no active
|
19
|
+
# projects, or no timesheet entries for the period specified.
|
20
|
+
#
|
21
|
+
# The output consists of the client's name, the text: 'Status Report (week
|
22
|
+
# ending <date>)', along with the timesheet entries returned. They are
|
23
|
+
# listed in project order, in entry order:
|
24
|
+
# ----------------------------------------
|
25
|
+
#
|
26
|
+
# ACME Co, Inc
|
27
|
+
#
|
28
|
+
# Status Report (week ending 9/19/20)
|
29
|
+
#
|
30
|
+
# I worked 0 hours.
|
31
|
+
# ----------------------------------------
|
32
|
+
#
|
33
|
+
class Status < Hammerhead::Command
|
34
|
+
include Hammerhead::Utils
|
35
|
+
|
36
|
+
def initialize client, options # :nodoc:
|
37
|
+
self.specified_client = client
|
38
|
+
self.options = options
|
39
|
+
configure_query_dates
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# :stopdoc:
|
44
|
+
#
|
45
|
+
def execute input: $stdin, output: $stdout
|
46
|
+
process_short_cut
|
47
|
+
connection = Harvest.connection
|
48
|
+
output.puts "Fetching details for specified client: #{specified_client}"
|
49
|
+
client = connection.client specified_client
|
50
|
+
unless client.active?
|
51
|
+
output.puts "#{client.name} is not active."
|
52
|
+
return
|
53
|
+
end
|
54
|
+
projects = connection.projects_for_client client
|
55
|
+
if projects.empty?
|
56
|
+
output.puts "#{client.name} has no active projects."
|
57
|
+
return
|
58
|
+
end
|
59
|
+
entries = connection.my_time_sheet_entries start_date, end_date
|
60
|
+
if entries.empty?
|
61
|
+
output.puts "There are no timesheet entries for the period specified: #{start_date} -> #{end_date}"
|
62
|
+
return
|
63
|
+
end
|
64
|
+
|
65
|
+
status_output = {
|
66
|
+
hours: 0.0,
|
67
|
+
projects: {},
|
68
|
+
entries: {}
|
69
|
+
}
|
70
|
+
|
71
|
+
projects.each do |project|
|
72
|
+
status_output[:projects][project.id] = project.code
|
73
|
+
end
|
74
|
+
|
75
|
+
entries.each do |entry|
|
76
|
+
next unless status_output[:projects].key? entry.project_id
|
77
|
+
|
78
|
+
status_output[:hours] += entry.hours
|
79
|
+
project_code = status_output[:projects][entry.project_id]
|
80
|
+
status_output[:entries][project_code] = [] unless status_output[:entries].key? project_code
|
81
|
+
status_output[:entries][project_code] << entry.notes
|
82
|
+
end
|
83
|
+
|
84
|
+
output.puts '----------------------------------------'
|
85
|
+
output.puts
|
86
|
+
output.puts client.name.to_s
|
87
|
+
output.puts
|
88
|
+
output.puts "Status Report (week ending #{end_date.strftime('%-m/%-d/%y')})"
|
89
|
+
output.puts
|
90
|
+
|
91
|
+
if status_output[:hours] > 0.0
|
92
|
+
output.puts "I worked #{status_output[:hours]} hours on the following:"
|
93
|
+
status_output[:entries].each do |code, _entries|
|
94
|
+
output.puts "\n[#{code}]"
|
95
|
+
_entries.each do |entry|
|
96
|
+
output.puts "- #{entry}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
else
|
100
|
+
output.puts 'I worked 0 hours.'
|
101
|
+
end
|
102
|
+
|
103
|
+
output.puts
|
104
|
+
output.puts '----------------------------------------'
|
105
|
+
rescue StandardError => e
|
106
|
+
Hammerhead.logger.error 'STATUS COMMAND ERROR:', e
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
attr_accessor :end_date, :options, :start_date, :specified_client
|
112
|
+
|
113
|
+
def configure_query_dates
|
114
|
+
today = Date.today
|
115
|
+
start_of_week = Date::DAYNAMES.index(Harvest.connection.week_start_day)
|
116
|
+
adjustment = today.wday - start_of_week
|
117
|
+
|
118
|
+
case today.wday
|
119
|
+
when 0 # Sunday
|
120
|
+
self.start_date = if start_of_week.zero?
|
121
|
+
today - 7
|
122
|
+
else
|
123
|
+
today - 6
|
124
|
+
end
|
125
|
+
self.end_date = start_date + 6
|
126
|
+
|
127
|
+
when 1 # Monday
|
128
|
+
if start_of_week.zero?
|
129
|
+
self.start_date = today - adjustment
|
130
|
+
self.end_date = start_date + adjustment
|
131
|
+
else
|
132
|
+
self.start_date = today - 7
|
133
|
+
self.end_date = start_date + 6
|
134
|
+
end
|
135
|
+
else
|
136
|
+
self.start_date = today - adjustment
|
137
|
+
self.end_date = start_date + adjustment
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def process_short_cut
|
142
|
+
return unless options['short_cut']
|
143
|
+
|
144
|
+
configuration = Hammerhead.configuration
|
145
|
+
|
146
|
+
return if digits? specified_client
|
147
|
+
|
148
|
+
client = configuration.client_shortcut specified_client
|
149
|
+
raise Hammerhead::Error, "Specified shortcut: '#{specified_client}' does not exist" if client.nil?
|
150
|
+
self.specified_client = client['id']
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tty-config'
|
4
|
+
|
5
|
+
module Hammerhead
|
6
|
+
##
|
7
|
+
# :markup: markdown
|
8
|
+
# Represents the configuration for the hammerhead tool. It wraps the [tty-config](https://rubygems.org/gems/tty-config)
|
9
|
+
# gem.
|
10
|
+
#
|
11
|
+
class Configuration
|
12
|
+
attr_reader :config # :nodoc:
|
13
|
+
|
14
|
+
##
|
15
|
+
# Creates a new instance of TTY::Config, configured with filename
|
16
|
+
# 'hammerhead.yml' and to look for said file in the current working directory
|
17
|
+
# or in the user's home directory.
|
18
|
+
#
|
19
|
+
def initialize
|
20
|
+
self.config = TTY::Config.new
|
21
|
+
config.append_path Dir.pwd # look in current working directory
|
22
|
+
config.append_path Dir.home # look in user home directory
|
23
|
+
config.filename = File.basename configuration_filename, '.*'
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# :category: harvest
|
28
|
+
# Returns the Harvest +password+ as defined in the configuration file.
|
29
|
+
#
|
30
|
+
# This configuration items is <b>required</b>.
|
31
|
+
#
|
32
|
+
def password
|
33
|
+
harvest_configuration['password']
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# :category: harvest
|
38
|
+
# Returns the Harvest +subdomain+ as defined in the configuration file.
|
39
|
+
#
|
40
|
+
# This configuration items is <b>required</b>.
|
41
|
+
#
|
42
|
+
def subdomain
|
43
|
+
harvest_configuration['subdomain']
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# :category: harvest
|
48
|
+
# Returns the Harvest +username+ as defined in the configuration file.
|
49
|
+
#
|
50
|
+
# This configuration items is <b>required</b>.
|
51
|
+
#
|
52
|
+
def username
|
53
|
+
harvest_configuration['username']
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# :category: clients
|
58
|
+
# Convenience method to obtain a configured +shortcut+. Returns a Hash or nil
|
59
|
+
#
|
60
|
+
# client_shortcut 'acme' => { id: 999999999, name: 'ACME Co, Inc' }
|
61
|
+
#
|
62
|
+
def client_shortcut shortcut
|
63
|
+
client_shortcuts[shortcut]
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# :category: clients
|
68
|
+
# Returns an Array of entries defined under +clients.shortcuts+
|
69
|
+
#
|
70
|
+
def client_shortcuts
|
71
|
+
config.fetch('clients.shortcuts', default: [])
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# :category: clients
|
76
|
+
# Returns an Array of client ids to be excluded from all operations.
|
77
|
+
#
|
78
|
+
def clients_to_exclude
|
79
|
+
config.fetch('clients.exclude', default: [])
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# :category: validation
|
84
|
+
# Performs 2 important checks: 1) if the file exists and 2) if it contains
|
85
|
+
# the required harvest information. If either of those fail this method
|
86
|
+
# raises an Hammerhead::Error.
|
87
|
+
#
|
88
|
+
def validate!
|
89
|
+
load_configuration!
|
90
|
+
validate_harvest_information
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
attr_writer :config # :nodoc:
|
96
|
+
|
97
|
+
def configuration_filename
|
98
|
+
'hammerhead.yml'
|
99
|
+
end
|
100
|
+
|
101
|
+
def harvest_configuration
|
102
|
+
config.fetch :harvest
|
103
|
+
end
|
104
|
+
|
105
|
+
def load_configuration!
|
106
|
+
unless config.exist?
|
107
|
+
raise Hammerhead::Error, "HarvestClient configuration file, '#{configuration_filename}' does not exist."
|
108
|
+
end
|
109
|
+
|
110
|
+
config.read
|
111
|
+
end
|
112
|
+
|
113
|
+
def validate_harvest_information
|
114
|
+
configuration_missing_messages = []
|
115
|
+
if harvest_configuration.nil?
|
116
|
+
configuration_missing_messages << "'#{configuration_filename}' does not define harvest configuration."
|
117
|
+
else
|
118
|
+
if subdomain.nil?
|
119
|
+
configuration_missing_messages << "'#{configuration_filename}' does not define harvest subdomain."
|
120
|
+
end
|
121
|
+
if username.nil?
|
122
|
+
configuration_missing_messages << "'#{configuration_filename}' does not define harvest username."
|
123
|
+
end
|
124
|
+
if password.nil?
|
125
|
+
configuration_missing_messages << "'#{configuration_filename}' does not define harvest password."
|
126
|
+
end
|
127
|
+
end
|
128
|
+
raise Hammerhead::Error, configuration_missing_messages.join("\n") unless configuration_missing_messages.empty?
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hammerhead
|
3
|
+
##
|
4
|
+
# Contains utility-type methods available for use throughout the tool.
|
5
|
+
#
|
6
|
+
module Utils
|
7
|
+
|
8
|
+
##
|
9
|
+
# Returns true if the specified +input+ consists of digits
|
10
|
+
#
|
11
|
+
# digits? '1234' => true
|
12
|
+
# digits? 'abcd' => false
|
13
|
+
#
|
14
|
+
# Uses a regular expression to determine if all the specified characters
|
15
|
+
# are numeric.
|
16
|
+
#
|
17
|
+
def digits? input
|
18
|
+
input.match?(/\A\d+\Z/)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/lib/harvest.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'harvest/connection'
|
4
|
+
|
5
|
+
##
|
6
|
+
# Exposes the Harvest API to Hammerhead.
|
7
|
+
#
|
8
|
+
module Harvest
|
9
|
+
class << self
|
10
|
+
##
|
11
|
+
# Returns the sole Harvest::Connection instance.
|
12
|
+
#
|
13
|
+
def connection
|
14
|
+
Harvest::Connection.instance
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
require 'harvested' # NOTE: support for Harvest API V1
|
5
|
+
|
6
|
+
module Harvest
|
7
|
+
##
|
8
|
+
# :markup: markdown
|
9
|
+
# Represents the link between Harvest and Hammerhead and the Harvest V1 API.
|
10
|
+
#
|
11
|
+
# Backed by ['harvested'](https://rubygems.org/gems/harvested) gem.
|
12
|
+
#
|
13
|
+
class Connection
|
14
|
+
include Singleton
|
15
|
+
include Hammerhead::Utils
|
16
|
+
|
17
|
+
##
|
18
|
+
# Use .instance to grab an initialied harvest connection:
|
19
|
+
# connection = Harvest::Connection.instance
|
20
|
+
#
|
21
|
+
# Because this attempts to establish a connection to the API, ensure a
|
22
|
+
# correctly defined 'hammerhead.yml' file exists.
|
23
|
+
#
|
24
|
+
# Returns Harvest.hardy_client
|
25
|
+
#
|
26
|
+
def initialize
|
27
|
+
new_connection!
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# This is the hammerhead user, as defined in by the harvest credentials. It
|
32
|
+
# is for this user the client list will be provided, and the status report
|
33
|
+
# will be generated.
|
34
|
+
#
|
35
|
+
def authenticated_user
|
36
|
+
harvest.account.who_am_i
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# For the specified +client_id+ return its Harvest definition.
|
41
|
+
#
|
42
|
+
# If +client_id+ contains alpha-characters NotImplementedError is raised.
|
43
|
+
#
|
44
|
+
def client client_id
|
45
|
+
raise NotImplementedError, 'Client by name is not implemented yet.' unless digits?(client_id)
|
46
|
+
harvest.clients.find client_id
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Return a list of clients. Currently only +options[:all]+ is supported.
|
51
|
+
# The default behavior is to only return 'active' clients.
|
52
|
+
#
|
53
|
+
# If the configuration file defines a list of ids to exclude, they're removed
|
54
|
+
# before 'active' or all clients are returned.
|
55
|
+
#
|
56
|
+
def clients options = {}
|
57
|
+
clients = harvest.clients.all.reject { |client| clients_to_exclude.include? client.id }
|
58
|
+
clients = clients.select { |client| client.active == true } unless options['all']
|
59
|
+
clients
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Return a list of timesheet entries between +start_date+ and +end_date+, inclusive.
|
64
|
+
#
|
65
|
+
# This is for the +authenticated_user+.
|
66
|
+
#
|
67
|
+
def my_time_sheet_entries start_date, end_date
|
68
|
+
harvest.reports.time_by_user authenticated_user, start_date, end_date
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Returns 'active' projects for the specified +client+.
|
73
|
+
#
|
74
|
+
# If the +client+ is not active, an empty list is returned.
|
75
|
+
#
|
76
|
+
def projects_for_client client
|
77
|
+
return [] unless client.active?
|
78
|
+
|
79
|
+
harvest.reports.projects_by_client(client).select(&:active?)
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Return begining of work week as defined in Harvest
|
84
|
+
#
|
85
|
+
def week_start_day
|
86
|
+
authenticated_user.company.week_start_day
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
attr_accessor :harvest
|
92
|
+
|
93
|
+
def new_connection!
|
94
|
+
Hammerhead.configuration.validate!
|
95
|
+
self.harvest = Harvest.hardy_client subdomain: subdomain, username: username, password: password if harvest.nil?
|
96
|
+
harvest
|
97
|
+
rescue StandardError => e
|
98
|
+
Hammerhead.logger.fatal 'Fatal:', e
|
99
|
+
end
|
100
|
+
|
101
|
+
def subdomain
|
102
|
+
Hammerhead.configuration.subdomain
|
103
|
+
end
|
104
|
+
|
105
|
+
def username
|
106
|
+
Hammerhead.configuration.username
|
107
|
+
end
|
108
|
+
|
109
|
+
def password
|
110
|
+
Hammerhead.configuration.password
|
111
|
+
end
|
112
|
+
|
113
|
+
def clients_to_exclude
|
114
|
+
Hammerhead.configuration.clients_to_exclude
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Define Rake Tasks 'internal' to Hammerhead development
|
3
|
+
|
4
|
+
def configuration_filename
|
5
|
+
'hammerhead.yml'
|
6
|
+
end
|
7
|
+
|
8
|
+
def example_configuration_filename
|
9
|
+
"#{configuration_filename}.example"
|
10
|
+
end
|
11
|
+
|
12
|
+
namespace :hh do
|
13
|
+
desc %(Flip Config File
|
14
|
+
|
15
|
+
Simple Rake Task to move the configuration file from one state to another.
|
16
|
+
|
17
|
+
)
|
18
|
+
task :flip_config_file do
|
19
|
+
if File.exist? configuration_filename
|
20
|
+
FileUtils.mv configuration_filename, example_configuration_filename, verbose: true
|
21
|
+
elsif File.exist? example_configuration_filename
|
22
|
+
FileUtils.mv example_configuration_filename, configuration_filename, verbose: true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hammerhead
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mel Riffe
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-09-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: tty
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.10.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.10.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.16'
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '2.0'
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1.16'
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '2.0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: harvested
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '4.0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '4.0'
|
61
|
+
description: Generate status reports from Harvest timesheets. TBD...
|
62
|
+
email:
|
63
|
+
- mel@juicyparts.com
|
64
|
+
executables:
|
65
|
+
- hammerhead
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files:
|
68
|
+
- README.md
|
69
|
+
- CHANGELOG.md
|
70
|
+
- CODE_OF_CONDUCT.md
|
71
|
+
- LICENSE.txt
|
72
|
+
files:
|
73
|
+
- CHANGELOG.md
|
74
|
+
- CODE_OF_CONDUCT.md
|
75
|
+
- LICENSE.txt
|
76
|
+
- README.md
|
77
|
+
- exe/hammerhead
|
78
|
+
- lib/hammerhead.rb
|
79
|
+
- lib/hammerhead/cli.rb
|
80
|
+
- lib/hammerhead/command.rb
|
81
|
+
- lib/hammerhead/commands/clients.rb
|
82
|
+
- lib/hammerhead/commands/status.rb
|
83
|
+
- lib/hammerhead/configuration.rb
|
84
|
+
- lib/hammerhead/utils.rb
|
85
|
+
- lib/hammerhead/version.rb
|
86
|
+
- lib/harvest.rb
|
87
|
+
- lib/harvest/connection.rb
|
88
|
+
- lib/tasks/hammerhead.rake
|
89
|
+
homepage: http://juicyparts.com/hammerhead
|
90
|
+
licenses:
|
91
|
+
- MIT
|
92
|
+
metadata:
|
93
|
+
allowed_push_host: https://rubygems.org
|
94
|
+
homepage_uri: http://juicyparts.com/hammerhead
|
95
|
+
source_code_uri: https://github.com/juicyparts/hammerhead
|
96
|
+
changelog_uri: https://github.com/juicyparts/hammerhead/blob/master/CHANGELOG.md
|
97
|
+
bug_tracker_uri: https://github.com/juicyparts/hammerhead/issues
|
98
|
+
documentation_uri: https://www.rubydoc.info/gems/hammerhead
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: 2.7.0
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubygems_version: 3.1.2
|
115
|
+
signing_key:
|
116
|
+
specification_version: 4
|
117
|
+
summary: Generate status reports from Harvest timesheets.
|
118
|
+
test_files: []
|