happy-commander 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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