happy-commander 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fee4b017af8d0d5e29bdd8bf7ac3b28f3d7a26ec
4
+ data.tar.gz: b97c0c62a98dda3e29ecc17e9b1616eccbeca83e
5
+ SHA512:
6
+ metadata.gz: b74692e4ba6ba9a8f56a343abdbb4947c536e5050bc0d9d771d34ecff469e76e1915b71d0c97de874d9f6283629342bae543ab11314cbf0c2bc54306b8d1f1b9
7
+ data.tar.gz: bf430f98495234b75684dcad0ed99ec1d2dcc0ab553e4cd525f3515b7a57dc5323304b0208da2b699621039263f5fe5ead8504ec64c8d8382dcd2fb1343294ad
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'rspec'
7
+ gem 'rake'
8
+ gem 'simplecov'
9
+ gem 'rubocop'
10
+ gem 'webmock'
11
+ end
12
+
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 jschmid1
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.
@@ -0,0 +1,45 @@
1
+ # Commander
2
+ Usage: commander [options] ...
3
+
4
+ -v, --vacation name,bool <NAME>,true/false(bool) comma is important
5
+
6
+ -f, --force name Set COMM manually <NAME>
7
+
8
+ -s, --status name Inspect history and status of <NAME>
9
+
10
+ -a, --auto Runs with default settings
11
+
12
+ -l, --list Lists all available Members.
13
+
14
+ -x, --setup Runs setup for your environment.
15
+
16
+ -h, --help Display this screen
17
+
18
+ -u, --version Print programs version
19
+
20
+ ## Installation
21
+
22
+ Add this line to your application's Gemfile:
23
+
24
+ gem 'happy-commander'
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install happy-commander
33
+
34
+ ## Usage
35
+
36
+ Start with --setup to set up your environment and configuration
37
+
38
+
39
+ ## Contributing
40
+
41
+ 1. Fork it ( https://github.com/[my-github-username]/commander/fork )
42
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
43
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
44
+ 4. Push to the branch (`git push origin my-new-feature`)
45
+ 5. Create a new Pull Request
@@ -0,0 +1,18 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ desc 'Run Rubocop'
4
+ task :rubocop do
5
+ sh 'bundle exec rubocop -c rubocop.yml'
6
+ end
7
+
8
+ task :console do
9
+ require 'irb'
10
+ require 'irb/completion'
11
+ ARGV.clear
12
+ IRB.start
13
+ end
14
+
15
+ desc 'Increase version of a gem'
16
+ task :bump do
17
+ sh 'gem bump --no-commit'
18
+ end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'commander/client'
4
+ require 'commander/version'
5
+ require 'commander/runner'
6
+ client = Commander::Client.new(ARGV.dup)
7
+ client.execute!
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'commander/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "happy-commander"
8
+ spec.version = Commander::VERSION
9
+ spec.authors = ["jschmid1"]
10
+ spec.email = ["jschmid@suse.de"]
11
+ spec.summary = %q{Automatically sets a Commanding officer of the Week.}
12
+ spec.description = %q{Easy, fair and trackable labor division in your team.}
13
+ spec.homepage = "http://rubygems.org/gems/happy-commander"
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_runtime_dependency 'ruby-trello', '=1.1.1'
22
+ spec.add_runtime_dependency 'json', '=1.7.7'
23
+ spec.add_runtime_dependency 'colorize', '=0.7.3'
24
+ end
@@ -0,0 +1,3 @@
1
+ # Commanding Officer of the week tool
2
+ require 'commander/version'
3
+ require 'yaml'
@@ -0,0 +1,90 @@
1
+ require 'optparse'
2
+ require 'commander/runner'
3
+ require 'commander/setup'
4
+ module Commander
5
+ # CLI with options
6
+ class Client
7
+
8
+ attr_accessor :options
9
+
10
+ def initialize(argv)
11
+ @options = {}
12
+ @argv = argv
13
+ extract_options
14
+ end
15
+
16
+ def execute!
17
+ runner = Commander::Runner
18
+ if @options[:force]
19
+ puts 'Forcing ..'
20
+ runner.new(@options).set_commander
21
+ elsif @options[:status]
22
+ puts 'Status output ..'
23
+ runner.new(@options).show_status(@options[:status])
24
+ elsif @options[:vacation]
25
+ puts 'Setting specified user as <on vacation>'
26
+ runner.new(@options).set_vacation_flag(@options[:vacation][0], @options[:vacation][1])
27
+ elsif @options[:auto]
28
+ puts 'Running with default settings..'
29
+ runner.new(@options).set_commander
30
+ elsif @options[:list]
31
+ puts 'Display all Members: '
32
+ runner.new(@options).list_all_members
33
+ elsif @options[:setup]
34
+ puts 'Running setup..'
35
+ Commander::Setup.configure
36
+ else
37
+ puts @optparse
38
+ exit
39
+ end
40
+ end
41
+
42
+ def extract_options
43
+ @optparse = OptionParser.new do |opts|
44
+
45
+ opts.banner = "Usage: commander [options] ..."
46
+
47
+ @options[:vacation] = false
48
+ opts.on( '-v', '--vacation name,bool', Array, '<NAME>,true/false(bool) comma is important' ) do |opt|
49
+ @options[:vacation] = opt
50
+ end
51
+
52
+ @options[:force] = false
53
+ opts.on( '-f', '--force name', 'Set COMM manually <NAME>' ) do |opt|
54
+ @options[:force] = opt
55
+ end
56
+
57
+ @options[:status] = false
58
+ opts.on( '-s', '--status name', 'Inspect history and status of <NAME>' ) do |opt|
59
+ @options[:status] = opt
60
+ end
61
+
62
+ @options[:auto] = false
63
+ opts.on( '-a', '--auto', 'Runs with default settings' ) do
64
+ @options[:auto] = true
65
+ end
66
+
67
+ @options[:list] = false
68
+ opts.on( '-l', '--list', 'Lists all available Members.' ) do |opt|
69
+ @options[:list] = opt
70
+ end
71
+
72
+ @options[:setup] = false
73
+ opts.on( '-x' ,'--setup', 'Runs setup for your environment.' ) do |opt|
74
+ @options[:setup] = opt
75
+ end
76
+
77
+ opts.on( '-h', '--help', 'Display this screen' ) do
78
+ puts opts
79
+ exit
80
+ end
81
+
82
+ opts.on( '-u', '--version', 'Print programs version' ) do
83
+ puts Commander::VERSION
84
+ exit
85
+ end
86
+ end
87
+ @optparse.parse(@argv)
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,3 @@
1
+ # Custom exceptions.
2
+ class InvalidInputException < Exception
3
+ end
@@ -0,0 +1,11 @@
1
+ module Commander
2
+
3
+ class Helpers
4
+
5
+ # no .to_bool
6
+ def self.to_boolean(state)
7
+ (state == 'true') ? @state = true : @state = false
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,156 @@
1
+ require 'yaml'
2
+ require 'commander/trello'
3
+ require 'commander/vacations'
4
+ require 'commander/helpers'
5
+ require 'trello'
6
+ require 'fileutils'
7
+ module Commander
8
+
9
+ FileUtils.mkdir_p("#{File.join(ENV['HOME'])}/.config/happy-commander/") unless Dir.exists?("#{ENV['HOME']}/.config/happy-commander")
10
+ FileUtils.cp ("#{File.dirname(__FILE__)}/../../config/.trello.yml"), ("#{File.join(Dir.home)}" + '/.config/happy-commander/') unless File.exists?(("#{File.join(Dir.home)}" + '/.config/happy-commander/.trello.yml'))
11
+ FileUtils.cp ("#{File.dirname(__FILE__)}/../../config/members.yml"), ("#{File.join(Dir.home)}" + '/.config/happy-commander/') unless File.exists?(("#{File.join(Dir.home)}" + '/.config/happy-commander/members.yml'))
12
+ CONFIG = YAML.load_file("#{File.join(ENV['HOME'])}/.config/happy-commander/.trello.yml")
13
+
14
+ class Runner
15
+
16
+ attr_accessor :options, :board, :selected_commander, :users
17
+
18
+ # Init
19
+ def initialize(opts = {})
20
+ @options = opts
21
+ @options[:force] = opts[:force]
22
+ @selected_commander = opts[:force] || opts[:status] || opts[:vacation]
23
+ @users = YAML.load_file("#{File.join(ENV['HOME'])}/.config/happy-commander/members.yml")
24
+ end
25
+
26
+ # Steps
27
+ def set_commander
28
+ import
29
+ find_card
30
+ update_vacations
31
+ select_commander if @options[:auto]
32
+ write_attributes if @options[:force]
33
+ manipulate_trello
34
+ puts "Chose: #{@selected_commander}"
35
+ end
36
+
37
+ # All Trello actions
38
+ def manipulate_trello
39
+ comment_on_card
40
+ delete_assigned_members
41
+ add_member_to_card
42
+ end
43
+
44
+ # Updates all vacations
45
+ def update_vacations
46
+ self.users.keys.each do |name|
47
+ @vacations = Commander::Vacations.find_vacations(self.users[name][:tel_name]) #tel_name
48
+ evaluate_vacations(name)
49
+ @users[name][:vacations] = @vacations
50
+ end
51
+ write_to_file('members', @users.to_yaml)
52
+ end
53
+
54
+ # Sets :vacation true if vacation
55
+ def set_vacation_flag(commander, state)
56
+ Commander::Helpers.to_boolean(state)
57
+ puts "#{commander} is on vacation"
58
+ @users[commander][:vacation] = true
59
+ end
60
+
61
+ # Check for timespans
62
+ def evaluate_vacations(commander)
63
+ parse_vacations.each do |check|
64
+ check[1] = check[0] unless check[1] # Rewrite if statement with catch to prevent this error?
65
+ if (check[0]..check[1]).cover?(Date.today)
66
+ set_vacation_flag(commander, 'true')
67
+ end
68
+ end
69
+ end
70
+
71
+ # Parsing vacation to computable format
72
+ def parse_vacations
73
+ split = @vacations.map { |x| x.split(' - ') }
74
+ split.map { |x| x.map { |b| Date.parse(b) } }
75
+ end
76
+
77
+ # Sorting logic
78
+ def select_commander
79
+ @selected_commander = Hash[@users.select { |_, v| !v[:vacation] }].sort_by{ |_, v| v[:times_commander] }
80
+ if @selected_commander.count > 1
81
+ if @selected_commander[0][1][:times_commander] == @selected_commander[1][1][:times_commander]
82
+ @selected_commander = @selected_commander.sort_by { |_,v| v[:date] }[0][0]
83
+ else
84
+ @selected_commander = @selected_commander[0][0]
85
+ end
86
+ else
87
+ @selected_commander = @selected_commander[0][0]
88
+ end
89
+ write_attributes
90
+ end
91
+
92
+ # Prints out the status
93
+ def show_status(commander)
94
+ puts "#{commander} was #{@users[commander][:times_commander] } times Commanding officer of the week."
95
+ puts "#{commander} is currently on vacation" if @users[commander][:vacation]
96
+ @users[commander][:vacations].each { |x| puts x}
97
+ end
98
+
99
+ # And writes
100
+ def write_attributes
101
+ users[@selected_commander][:vacation] = false
102
+ users[@selected_commander][:times_commander] = count_up
103
+ users[@selected_commander][:date] = Time.now
104
+ write_to_file('members', @users.to_yaml)
105
+ end
106
+
107
+ # Delete assigned commander from Trello Card
108
+ def delete_assigned_members
109
+ @card.members.each{|member| @card.remove_member member}
110
+ end
111
+
112
+ # Adds commander to Trello Card
113
+ def add_member_to_card
114
+ @trello.add_commander_to_card(find_member, @card)
115
+ end
116
+
117
+ # List all available Users
118
+ def list_all_members
119
+ @users.each { |x| puts "-#{x.first}"}
120
+ end
121
+
122
+ # Finds the Commander Card on Trello
123
+ def find_card
124
+ @card = @trello.find_card_by_id(CONFIG['card_id']) # replace when move to real board
125
+ end
126
+
127
+ # Finds the member on Trello
128
+ def find_member
129
+ @trello.find_member_by_username(users[@selected_commander][:trello_name])
130
+ end
131
+
132
+ # Increments the counter
133
+ def count_up
134
+ users[@selected_commander][:times_commander] += 1
135
+ end
136
+
137
+ # Writes to yaml
138
+ def write_to_file(filename, content)
139
+ File.open("#{File.join(Dir.home)}/.config/happy-commander/#{filename}.yml", 'w') do |f|
140
+ f.write(content)
141
+ end
142
+ end
143
+
144
+ # Imports TrelloConnection
145
+ def import
146
+ @trello = Commander::TrelloConnection.new
147
+ end
148
+
149
+ # Comments on Trello Card
150
+ def comment_on_card
151
+ @comment_string = "@#{@users[@selected_commander][:trello_name]} is your commanding officer for the next 7 Days."
152
+ @trello.comment_on_card(@comment_string, @card)
153
+ end
154
+
155
+ end
156
+ end
@@ -0,0 +1,145 @@
1
+ require 'yaml'
2
+ require 'colorize'
3
+ require 'fileutils'
4
+ require_relative 'exceptions'
5
+ module Commander
6
+
7
+ class Setup
8
+
9
+ attr_accessor :conf
10
+ @conf = YAML.load_file("#{File.join(ENV['HOME'])}/.config/happy-commander/.trello.yml")
11
+
12
+
13
+ def self.get_user_input
14
+ $stdin.gets.chomp
15
+ end
16
+
17
+ def self.configure
18
+ system('clear')
19
+ puts 'Provide your Trello Board ID'.green
20
+ puts 'If you don\'t know where to find it visit your board.'
21
+ puts "https://trello.com/b/" + "YOURBOARDID".green+"/boardname etc.."
22
+ printf '>>'
23
+ @conf['board_id'] = get_user_input
24
+ system('clear')
25
+
26
+ puts 'Provide your Trello consumer key.'.green
27
+ puts 'You can generate this key on.'
28
+ puts 'Https://trello.com/1/appKey/generate'
29
+ printf '>>'
30
+ @conf['consumerkey'] = get_user_input
31
+ system('clear')
32
+
33
+ puts 'Provide your Trello consumer secret.'.green
34
+ puts 'You can generate this key on.'
35
+ puts 'Https://trello.com/1/appKey/generate'
36
+ printf '>>'
37
+ @conf['consumersecret'] = get_user_input
38
+ system('clear')
39
+
40
+
41
+ puts 'Finally provide the generated token.'.green
42
+ puts 'Which you can get here.'
43
+ puts "https://trello.com/1/authorize?key=#{@conf['consumerkey']}&name=happy-commander&expiration=never&response_type=token&scope=read,write"
44
+ printf '>>'
45
+ @conf['oauthtoken'] = get_user_input
46
+ system('clear')
47
+
48
+ puts 'Specify the card id (comments and assignments on this card).'.green
49
+ puts 'See in card description.'
50
+ puts 'Or in browser url.'
51
+ puts "e.g https://trello.com/c/somecard/"+"2075".green+"-commanding-officer-of-the-week"
52
+ printf '>>'
53
+ @conf['card_id'] = get_user_input
54
+ system('clear')
55
+
56
+ puts 'Set the interval.'.green
57
+ puts 'E.g. for every tuesday'
58
+ puts 'Write: tuesday, or weekdays'
59
+ puts 'At what time?'
60
+ puts 'Write: 1pm, 10pm, 2pm, 1am and so on..'
61
+ puts 'Or: raw cron syntax'
62
+ puts 'Like: 0 0 27-31 * *'
63
+ puts ''
64
+ puts 'What syntax will you provide?'
65
+ puts '1. Written language'.green
66
+ puts '2. Raw cron syntax'.green
67
+ puts '3. None'
68
+ printf '>>'
69
+ choose(get_user_input)
70
+ system('clear')
71
+ write_to_file('.trello', @conf.to_yaml)
72
+ end
73
+
74
+ def self.choose(choice)
75
+ case choice.to_i
76
+ when 1
77
+ puts 'Chose written language:'
78
+ puts 'Day'
79
+ puts 'e.g. Monday, Tuesday, ...'
80
+ printf '>>'
81
+ pick_cron_day
82
+ puts 'Time..'
83
+ puts 'e.g. 11, 21, 24, 8, 3'
84
+ printf '>>'
85
+ @hour = pick_cron_time
86
+ puts 'Put this in your cron'
87
+ puts 'Edit it with crontab -e'
88
+ puts ("#{concat_cron_syntax} " + " /bin/bash -l -c " + "'"+"#{%x[which commander].chomp || %x[which commander2.0].chomp} -a"+"'").green
89
+
90
+ when 2
91
+ puts 'Chose raw cron syntax'
92
+ puts 'e.g. 0 0 27-31 * *'
93
+ printf '>>'
94
+ raw_syn = get_user_input
95
+ puts 'Put this in your cron'
96
+ puts 'Edit it with crontab -e'
97
+ puts ("#{raw_syn} " + " /bin/bash -l -c " + "'"+"#{%x[which commander].chomp || %x[which commander2.0].chomp} -a"+"'").green
98
+ when 3
99
+ write_to_file('.trello', @conf.to_yaml)
100
+ exit('Success')
101
+ else
102
+ puts 'Nothing happend.'
103
+ end
104
+
105
+ end
106
+
107
+ def self.concat_cron_syntax
108
+ "0 #{@hour} 0 0 #{@cron_day}"
109
+ end
110
+
111
+ def self.pick_cron_time
112
+ time = get_user_input.to_i
113
+ unless (1..24).cover?(time)
114
+ raise InvalidInputException, "Not a valid timeframe: #{time}"
115
+ end
116
+ puts "selected: #{time}"
117
+ @hour = time
118
+ rescue InvalidInputException => e
119
+ puts e.message
120
+ puts "Valid values are: [1, 2, 3...22, 23, 24]"
121
+ retry
122
+ end
123
+
124
+ def self.pick_cron_day
125
+ day = get_user_input
126
+ weekdays = %w(Sunday Monday Tuesday Wednesday Thursday Friday Saturday)
127
+ unless weekdays.include?(day)
128
+ raise InvalidInputException, "Not a valid weekday: '#{day}'"
129
+ end
130
+ puts "selected: #{day}"
131
+ @cron_day = weekdays.index(day)
132
+ rescue InvalidInputException => e
133
+ puts e.message
134
+ puts "Valid options are: #{weekdays}"
135
+ retry
136
+ end
137
+
138
+ def self.write_to_file(filename, content)
139
+ File.open("#{File.join(Dir.home)}/.config/happy-commander/#{filename}.yml", 'w') do |f|
140
+ f.write(content)
141
+ end
142
+ end
143
+
144
+ end
145
+ end