renuo-cli 1.5.0 → 1.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rspec +1 -1
- data/.rubocop.yml +2 -1
- data/.semaphore/master-deploy.yml +19 -0
- data/.semaphore/semaphore.yml +39 -0
- data/README.md +10 -16
- data/Rakefile +0 -3
- data/lib/renuo/cli.rb +40 -3
- data/lib/renuo/cli/app/configure_semaphore.rb +58 -0
- data/lib/renuo/cli/app/fetch_emails.rb +23 -5
- data/lib/renuo/cli/app/redmine/csv_base_service.rb +54 -0
- data/lib/renuo/cli/app/redmine/issue.rb +23 -0
- data/lib/renuo/cli/app/services/renuo_cli_config.rb +29 -0
- data/lib/renuo/cli/app/templates/semaphore-deploy.yml.erb +25 -0
- data/lib/renuo/cli/app/templates/semaphore.yml.erb +70 -0
- data/lib/renuo/cli/app/toggl/detail.rb +30 -0
- data/lib/renuo/cli/app/toggl/time_entry.rb +30 -0
- data/lib/renuo/cli/app/toggl/user.rb +24 -0
- data/lib/renuo/cli/app/toggl/workspace.rb +17 -0
- data/lib/renuo/cli/app/toggl_redmine_comparator.rb +145 -0
- data/lib/renuo/cli/app/work.rb +94 -0
- data/lib/renuo/cli/version.rb +1 -1
- data/renuo-cli.gemspec +4 -2
- metadata +62 -21
- data/.coveralls.yml +0 -1
- data/.travis.yml +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 577c679e818462872dd5489f96493b109af10e72
|
4
|
+
data.tar.gz: 6d3b7b14afe1fe44c114994d033b9eb8993d7f75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 552508988e60a07668c338010680213c1f016be6fd8b2170cf129ce7e8937b895bc3b3895bb511c2777daed3958a863c1bb0dce75df937252e6bec0b581c53d4
|
7
|
+
data.tar.gz: edc406e3f95a25a38651c6b06b4a950076bff3c25a429da050030b85455838c0e9cdb89ccaec296fd3134985e86e6e25df920af28be6828ab686a3765b3046c0
|
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
AllCops:
|
2
2
|
Include:
|
3
|
-
- 'lib
|
3
|
+
- 'lib/**/*.rb'
|
4
4
|
- 'spec/**/*'
|
5
5
|
- '*.gemspec'
|
6
6
|
Exclude:
|
@@ -9,6 +9,7 @@ AllCops:
|
|
9
9
|
- 'lib/renuo/cli/app/heroku_users'
|
10
10
|
- 'lib/renuo/cli/app/fetch_all_emails'
|
11
11
|
- 'lib/renuo/cli/app/create_heroku_app'
|
12
|
+
- 'vendor/**/*'
|
12
13
|
|
13
14
|
Naming/FileName:
|
14
15
|
Exclude:
|
@@ -0,0 +1,19 @@
|
|
1
|
+
version: v1.0
|
2
|
+
name: master-deploy
|
3
|
+
agent:
|
4
|
+
machine:
|
5
|
+
type: e1-standard-2
|
6
|
+
os_image: ubuntu1804
|
7
|
+
|
8
|
+
blocks:
|
9
|
+
- name: master-deploy
|
10
|
+
task:
|
11
|
+
secrets:
|
12
|
+
- name: rubygems-deploy
|
13
|
+
jobs:
|
14
|
+
- name: master-deploy
|
15
|
+
commands:
|
16
|
+
- checkout --use-cache
|
17
|
+
- gem build renuo-cli
|
18
|
+
- chmod 0600 ~/.gem/credentials
|
19
|
+
- gem push renuo-cli-*.gem
|
@@ -0,0 +1,39 @@
|
|
1
|
+
version: "v1.0"
|
2
|
+
name: renuo-cli
|
3
|
+
agent:
|
4
|
+
machine:
|
5
|
+
type: e1-standard-2
|
6
|
+
os_image: ubuntu1804
|
7
|
+
auto_cancel:
|
8
|
+
running:
|
9
|
+
when: "true"
|
10
|
+
|
11
|
+
blocks:
|
12
|
+
- name: tests
|
13
|
+
execution_time_limit:
|
14
|
+
minutes: 10
|
15
|
+
task:
|
16
|
+
secrets:
|
17
|
+
- name: renuo-cli
|
18
|
+
env_vars:
|
19
|
+
- name: RAILS_ENV
|
20
|
+
value: test
|
21
|
+
prologue:
|
22
|
+
commands:
|
23
|
+
- checkout --use-cache
|
24
|
+
- cache restore
|
25
|
+
- gem update bundler
|
26
|
+
- bundle install -j 4 --path vendor/bundle
|
27
|
+
- cache store
|
28
|
+
jobs:
|
29
|
+
- name: tests
|
30
|
+
commands:
|
31
|
+
- bin/check
|
32
|
+
epilogue:
|
33
|
+
on_fail:
|
34
|
+
commands:
|
35
|
+
- artifact push job --expire-in 2w log/test.log
|
36
|
+
- artifact push job --expire-in 2w tmp/screenshots
|
37
|
+
promotions:
|
38
|
+
- name: master
|
39
|
+
pipeline_file: master-deploy.yml
|
data/README.md
CHANGED
@@ -1,10 +1,6 @@
|
|
1
|
-
|
2
|
-
[![Coverage Status](https://coveralls.io/repos/renuo/renuo-cli/badge.svg?branch=master&service=github)](https://coveralls.io/github/renuo/renuo-cli?branch=master)
|
3
|
-
[![Code Climate](https://codeclimate.com/github/renuo/renuo-cli/badges/gpa.svg)](https://codeclimate.com/github/renuo/renuo-cli)
|
1
|
+
# Renuo CLI
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
The Renuo command line. Used for various (internal) stuff.
|
3
|
+
The [Renuo](http://renuo.ch) command line. Used for various Renuo tasks
|
8
4
|
|
9
5
|
## Installation
|
10
6
|
|
@@ -36,18 +32,17 @@ To release a new version, update the version number in `version.rb`, and then ru
|
|
36
32
|
|
37
33
|
## Release
|
38
34
|
|
39
|
-
|
35
|
+
* Bump the version number in `lib/renuo/cli/version.rb` and commit to `master`
|
36
|
+
|
37
|
+
### Automatic
|
38
|
+
|
39
|
+
* Deploy through Semaphore console by starting a promotion to master
|
40
|
+
|
41
|
+
### Manual
|
40
42
|
|
41
43
|
```sh
|
42
|
-
git flow release start [.....]
|
43
|
-
# adjust version.rb
|
44
|
-
bundle install
|
45
|
-
git commit -av
|
46
|
-
git flow release finish [.....]
|
47
|
-
git push origin develop:develop
|
48
|
-
git push origin master:master --tags
|
49
44
|
gem build renuo-cli.gemspec
|
50
|
-
gem push renuo-cli
|
45
|
+
gem push renuo-cli-*.gem
|
51
46
|
```
|
52
47
|
|
53
48
|
## Contributing
|
@@ -59,4 +54,3 @@ the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
|
59
54
|
## License
|
60
55
|
|
61
56
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
62
|
-
|
data/Rakefile
CHANGED
@@ -1,11 +1,8 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
2
|
require 'rspec/core/rake_task'
|
3
|
-
require 'coveralls/rake/task'
|
4
3
|
require 'cucumber/rake/task'
|
5
4
|
|
6
5
|
RSpec::Core::RakeTask.new(:spec)
|
7
6
|
Cucumber::Rake::Task.new
|
8
|
-
Coveralls::RakeTask.new
|
9
7
|
|
10
|
-
task test_with_coveralls: [:spec, :cucumber, 'coveralls:push']
|
11
8
|
task default: %i[spec cucumber]
|
data/lib/renuo/cli.rb
CHANGED
@@ -2,6 +2,7 @@ require 'renuo/cli/version'
|
|
2
2
|
require 'rubygems'
|
3
3
|
require 'gems'
|
4
4
|
require 'colorize'
|
5
|
+
require 'renuo/cli/app/services/renuo_cli_config'
|
5
6
|
require 'renuo/cli/app/name_display'
|
6
7
|
require 'renuo/cli/app/local_storage'
|
7
8
|
require 'renuo/cli/app/list_large_git_files'
|
@@ -11,11 +12,14 @@ require 'renuo/cli/app/create_aws_project'
|
|
11
12
|
require 'renuo/cli/app/create_heroku_app'
|
12
13
|
require 'renuo/cli/app/configure_sentry'
|
13
14
|
require 'renuo/cli/app/create_new_logins'
|
14
|
-
require 'renuo/cli/app/
|
15
|
-
require 'renuo/cli/app/
|
16
|
-
require 'renuo/cli/app/
|
15
|
+
require 'renuo/cli/app/work'
|
16
|
+
require 'renuo/cli/app/release_project'
|
17
|
+
require 'renuo/cli/app/fetch_emails'
|
18
|
+
require 'renuo/cli/app/heroku_users'
|
17
19
|
require 'renuo/cli/app/setup_uptimerobot'
|
18
20
|
require 'renuo/cli/app/release_xing'
|
21
|
+
require 'renuo/cli/app/configure_semaphore'
|
22
|
+
require 'renuo/cli/app/toggl_redmine_comparator'
|
19
23
|
|
20
24
|
module Renuo
|
21
25
|
class CLI
|
@@ -128,6 +132,19 @@ module Renuo
|
|
128
132
|
end
|
129
133
|
end
|
130
134
|
|
135
|
+
command 'work' do |c|
|
136
|
+
c.syntax = 'renuo work'
|
137
|
+
c.summary = 'A utility command to start working on a ticket.'
|
138
|
+
c.description = 'When you start working on a feature, it will jump to the project folder, '\
|
139
|
+
'start a new feature with the ticket number,'\
|
140
|
+
'move the ticket in "In progress" state on Redmine and start Toggl with the '\
|
141
|
+
'ticket number or add the ticket number to the running one if there was none.'
|
142
|
+
c.example 'renuo work start kinova 1234', 'start working on ticket 1234 on kinova project'
|
143
|
+
c.action do|args|
|
144
|
+
Work.new.run(args)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
131
148
|
command 'release' do |c|
|
132
149
|
c.syntax = 'renuo release'
|
133
150
|
c.summary = 'Release a projects state of develop (on github) to master in one command.'
|
@@ -203,6 +220,26 @@ module Renuo
|
|
203
220
|
ReleaseXing.new.run
|
204
221
|
end
|
205
222
|
end
|
223
|
+
|
224
|
+
command 'configure-semaphore' do |c|
|
225
|
+
c.syntax = 'renuo configure-semaphore'
|
226
|
+
c.summary = 'Adds standard semaphore configuration files to a project and creates the notifications'
|
227
|
+
c.description = 'Run this command with a project, to add the semaphore configuration files '\
|
228
|
+
'and create notifications.'
|
229
|
+
c.action do |args|
|
230
|
+
ConfigureSemaphore.new.call
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
command 'toggl-redmine' do |c|
|
235
|
+
c.syntax = 'renuo toggl-redmine'
|
236
|
+
c.summary = 'Compares your time entries between Toggl and Redmine'
|
237
|
+
c.description = 'This command extracts your time entries in Toggl and in Redmine and checks if they are'\
|
238
|
+
' consistant. It can help you in your time booking to find if you booked something wrong'
|
239
|
+
c.action do |args|
|
240
|
+
TogglRedmineComparator.call
|
241
|
+
end
|
242
|
+
end
|
206
243
|
end
|
207
244
|
end
|
208
245
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'commander'
|
2
|
+
require_relative './environments'
|
3
|
+
|
4
|
+
class ConfigureSemaphore
|
5
|
+
attr_accessor :project_name, :environment
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@project_name = File.basename(Dir.getwd)
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
return unless semaphore_cli_installed?
|
13
|
+
FileUtils.mkdir_p('.semaphore')
|
14
|
+
write_or_warn('.semaphore/semaphore.yml', render('templates/semaphore.yml.erb'))
|
15
|
+
%w[master develop testing].each do |environment|
|
16
|
+
@environment = environment
|
17
|
+
write_or_warn(".semaphore/#{environment}-deploy.yml", render('templates/semaphore-deploy.yml.erb'))
|
18
|
+
end
|
19
|
+
create_semaphore_notification
|
20
|
+
create_semaphore_secrets
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def semaphore_cli_installed?
|
26
|
+
semaphore_cli_installed = `sem context | grep '*'`.strip == '* renuo_semaphoreci_com'
|
27
|
+
warn('You need to install and configure Semaphore CLI to run this command.') unless semaphore_cli_installed
|
28
|
+
semaphore_cli_installed
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_semaphore_notification
|
32
|
+
system("sem create notifications #{project_name} "\
|
33
|
+
"--projects #{project_name} "\
|
34
|
+
'--branches "master,develop,testing" '\
|
35
|
+
"--slack-channels \"#project-#{project_name}\" "\
|
36
|
+
'--slack-endpoint "https://hooks.slack.com/services/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"')
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_semaphore_secrets
|
40
|
+
system("sem create secret #{project_name}")
|
41
|
+
end
|
42
|
+
|
43
|
+
def render(template_file)
|
44
|
+
file_path = File.join(File.dirname(__FILE__), template_file)
|
45
|
+
semaphore_template = File.read(file_path)
|
46
|
+
renderer = ERB.new(semaphore_template)
|
47
|
+
renderer.result(binding)
|
48
|
+
end
|
49
|
+
|
50
|
+
def write_or_warn(file_path, content)
|
51
|
+
if File.exist?(file_path)
|
52
|
+
warn("#{file_path} exists already. I will not overwrite it.")
|
53
|
+
else
|
54
|
+
File.write(file_path, content)
|
55
|
+
say("#{file_path} added.")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -2,16 +2,34 @@ require 'net/http'
|
|
2
2
|
require 'uri'
|
3
3
|
|
4
4
|
class FetchEmails
|
5
|
-
def initialize
|
5
|
+
def initialize
|
6
|
+
@email_list_url = 'https://docs.google.com/spreadsheets/d/e/2PACX-1vSqPiedBeGk0N75cxZApEohj5LrIWlHWUxTjfhkmK9aOsUltcqCn24sD1haIasUjVfd8UT8VdUKUc4h/pub?gid=703649940&single=true&output=csv'
|
7
|
+
end
|
6
8
|
|
7
9
|
def fetch_emails
|
8
|
-
|
9
|
-
response = Net::
|
10
|
-
response
|
10
|
+
response = get_emails(@email_list_url)
|
11
|
+
response = handle_redirection(response) if response.is_a?(Net::HTTPRedirection)
|
12
|
+
format_response(response)
|
11
13
|
end
|
12
14
|
|
13
15
|
def run(_args)
|
14
|
-
say '# Here is a complete
|
16
|
+
say '# Here is a complete list of Renuo email addresses'.colorize :green
|
15
17
|
say fetch_emails.join("\n")
|
16
18
|
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def get_emails(url)
|
23
|
+
uri = URI.parse(url)
|
24
|
+
Net::HTTP.get_response(uri)
|
25
|
+
end
|
26
|
+
|
27
|
+
def handle_redirection(response)
|
28
|
+
location = response['location']
|
29
|
+
get_emails(location)
|
30
|
+
end
|
31
|
+
|
32
|
+
def format_response(response)
|
33
|
+
response.body.gsub(/\r\n/, "\n").split("\n").reject { |add| add == 'n/a' }
|
34
|
+
end
|
17
35
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module Redmine
|
4
|
+
class CsvBaseService
|
5
|
+
API_LOCATION = 'https://redmine.renuo.ch'.freeze
|
6
|
+
|
7
|
+
def initialize(token)
|
8
|
+
@token = token
|
9
|
+
end
|
10
|
+
|
11
|
+
def get
|
12
|
+
http_response = http_request(generate_url)
|
13
|
+
encoded_body = http_response.body.force_encoding('ISO-8859-1').encode('UTF-8')
|
14
|
+
csv = parse_csv(encoded_body)
|
15
|
+
parse_results(csv)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def generate_url
|
21
|
+
URI("#{API_LOCATION}/time_entries/report.csv?#{query}&key=#{@token}")
|
22
|
+
end
|
23
|
+
|
24
|
+
def http_request(url)
|
25
|
+
req = Net::HTTP::Get.new(url)
|
26
|
+
Net::HTTP.start(url.hostname, url.port, use_ssl: true) do |http|
|
27
|
+
http.request(req)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def query
|
32
|
+
# to be implemented in concrete service
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_results(_csv)
|
36
|
+
# to be implemented in concrete service
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_csv(body)
|
40
|
+
separated_csv_entries = CSV.parse(body, col_sep: ',')
|
41
|
+
keys = separated_csv_entries.shift[1..-2]
|
42
|
+
entries = separated_csv_entries.shift[1..-2]
|
43
|
+
Hash[keys.zip(entries)]
|
44
|
+
rescue CSV::MalformedCSVError
|
45
|
+
raise_bad_data_error
|
46
|
+
end
|
47
|
+
|
48
|
+
def raise_bad_data_error
|
49
|
+
error = 'Malformed CSV, please use comma delimiters (Redmine language setting?)'
|
50
|
+
Rails.logger.error error
|
51
|
+
raise Redmine::BadData, error
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'active_resource'
|
2
|
+
|
3
|
+
module Redmine
|
4
|
+
class Issue < ActiveResource::Base
|
5
|
+
STATUSES = {
|
6
|
+
to_start: 9,
|
7
|
+
planned: 15,
|
8
|
+
in_progress: 2,
|
9
|
+
qa: 12
|
10
|
+
}.freeze
|
11
|
+
|
12
|
+
self.site = 'https://redmine.renuo.ch'
|
13
|
+
self.include_root_in_json = true
|
14
|
+
|
15
|
+
def self.headers
|
16
|
+
{ 'X-Redmine-API-Key' => RenuoCliConfig.redmine_api_key }
|
17
|
+
end
|
18
|
+
|
19
|
+
def html_url
|
20
|
+
"#{self.class.site}issues/#{id}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
class RenuoCliConfig
|
4
|
+
CONFIG_FILE_PATH = "#{File.expand_path('~')}/.renuo_cli".freeze
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def redmine_api_key
|
8
|
+
get_config_value('REDMINE_API_KEY', 'https://redmine.renuo.ch/my/account')
|
9
|
+
end
|
10
|
+
|
11
|
+
def toggl_api_token
|
12
|
+
get_config_value('TOGGL_API_TOKEN', 'https://toggl.com/app/profile')
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def get_config_value(name, open_url)
|
18
|
+
FileUtils.touch(CONFIG_FILE_PATH)
|
19
|
+
config = YAML.load_file(CONFIG_FILE_PATH, fallback: {})
|
20
|
+
value = config[name]
|
21
|
+
return value if value
|
22
|
+
system("open #{open_url}")
|
23
|
+
value = ask("You haven't set your #{name}, yet. Please provide one:")
|
24
|
+
config[name] = value
|
25
|
+
File.write(CONFIG_FILE_PATH, config.to_yaml)
|
26
|
+
value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
version: v1.0
|
2
|
+
name: <%= environment %>-deploy
|
3
|
+
agent:
|
4
|
+
machine:
|
5
|
+
type: e1-standard-2
|
6
|
+
os_image: ubuntu1804
|
7
|
+
|
8
|
+
blocks:
|
9
|
+
- name: <%= environment %>-deploy
|
10
|
+
task:
|
11
|
+
secrets:
|
12
|
+
- name: heroku-deploy
|
13
|
+
env_vars:
|
14
|
+
- name: HEROKU_REMOTE
|
15
|
+
value: https://git.heroku.com/<%= project_name %>-<%= environment %>.git
|
16
|
+
jobs:
|
17
|
+
- name: <%= environment %>-deploy
|
18
|
+
commands:
|
19
|
+
- checkout --use-cache
|
20
|
+
- ssh-keyscan -H heroku.com >> ~/.ssh/known_hosts
|
21
|
+
- chmod 600 ~/.ssh/id_rsa_semaphore_heroku
|
22
|
+
- ssh-add ~/.ssh/id_rsa_semaphore_heroku
|
23
|
+
- git config --global url.ssh://git@heroku.com/.insteadOf https://git.heroku.com/
|
24
|
+
- git remote add heroku $HEROKU_REMOTE
|
25
|
+
- git push heroku -f $SEMAPHORE_GIT_BRANCH:master
|
@@ -0,0 +1,70 @@
|
|
1
|
+
version: "v1.0"
|
2
|
+
name: <%= project_name %>
|
3
|
+
agent:
|
4
|
+
machine:
|
5
|
+
type: e1-standard-2
|
6
|
+
os_image: ubuntu1804
|
7
|
+
auto_cancel:
|
8
|
+
running:
|
9
|
+
when: "true"
|
10
|
+
|
11
|
+
blocks:
|
12
|
+
- name: cache
|
13
|
+
execution_time_limit:
|
14
|
+
minutes: 10
|
15
|
+
dependencies: []
|
16
|
+
task:
|
17
|
+
secrets:
|
18
|
+
- name: <%= project_name %>
|
19
|
+
jobs:
|
20
|
+
- name: cache
|
21
|
+
commands:
|
22
|
+
- checkout --use-cache
|
23
|
+
- cache restore nvm-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),nvm-$SEMAPHORE_GIT_BRANCH,nvm-develop,nvm-master
|
24
|
+
- cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH,gems-develop,gems-master
|
25
|
+
- cache restore yarn-cache-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),yarn-cache-$SEMAPHORE_GIT_BRANCH,yarn-cache-develop,yarn-cache-master
|
26
|
+
- cache restore node-modules-$SEMAPHORE_GIT_BRANCH-$(checksum yarn.lock),node-modules-$SEMAPHORE_GIT_BRANCH,node-modules-develop,node-modules-master
|
27
|
+
- bundle install --deployment -j 4 --path vendor/bundle
|
28
|
+
- nvm install
|
29
|
+
- bin/yarn install --cache-folder ~/.cache/yarn
|
30
|
+
- cache store
|
31
|
+
- name: tests
|
32
|
+
execution_time_limit:
|
33
|
+
minutes: 10
|
34
|
+
dependencies: ['cache']
|
35
|
+
task:
|
36
|
+
secrets:
|
37
|
+
- name: <%= project_name %>
|
38
|
+
env_vars:
|
39
|
+
- name: DATABASE_URL
|
40
|
+
value: postgresql://postgres@localhost/test?encoding=utf8
|
41
|
+
- name: RAILS_ENV
|
42
|
+
value: test
|
43
|
+
prologue:
|
44
|
+
commands:
|
45
|
+
- checkout --use-cache
|
46
|
+
- cache restore nvm-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),nvm-$SEMAPHORE_GIT_BRANCH,nvm-develop,nvm-master
|
47
|
+
- cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH,gems-develop,gems-master
|
48
|
+
- cache restore yarn-cache-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),yarn-cache-$SEMAPHORE_GIT_BRANCH,yarn-cache-develop,yarn-cache-master
|
49
|
+
- cache restore node-modules-$SEMAPHORE_GIT_BRANCH-$(checksum yarn.lock),node-modules-$SEMAPHORE_GIT_BRANCH,node-modules-develop,node-modules-master
|
50
|
+
- bundle install --deployment --path vendor/bundle
|
51
|
+
- bin/yarn install --cache-folder ~/.cache/yarn
|
52
|
+
- sem-service start postgres
|
53
|
+
- bundle exec rails db:create db:schema:load
|
54
|
+
jobs:
|
55
|
+
- name: tests
|
56
|
+
commands:
|
57
|
+
- bin/check
|
58
|
+
promotions:
|
59
|
+
- name: develop
|
60
|
+
pipeline_file: develop-deploy.yml
|
61
|
+
auto_promote:
|
62
|
+
when: "result = 'passed' and branch = 'develop'"
|
63
|
+
- name: master
|
64
|
+
pipeline_file: master-deploy.yml
|
65
|
+
auto_promote:
|
66
|
+
when: "result = 'passed' and branch = 'master'"
|
67
|
+
- name: testing
|
68
|
+
pipeline_file: testing-deploy.yml
|
69
|
+
auto_promote:
|
70
|
+
when: "result = 'passed' and branch = 'testing'"
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'active_resource'
|
2
|
+
|
3
|
+
module Toggl
|
4
|
+
module CustomJsonFormat
|
5
|
+
include ActiveResource::Formats::JsonFormat
|
6
|
+
|
7
|
+
# rubocop:disable Style/ModuleFunction
|
8
|
+
extend self
|
9
|
+
# rubocop:enable Style/ModuleFunction
|
10
|
+
|
11
|
+
def decode(json)
|
12
|
+
ActiveSupport::JSON.decode(json)['data']
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Detail < ActiveResource::Base
|
17
|
+
self.format = CustomJsonFormat
|
18
|
+
self.site = 'https://toggl.com/reports/api/v2'
|
19
|
+
self.include_root_in_json = true
|
20
|
+
self.include_format_in_path = false
|
21
|
+
|
22
|
+
def self.user
|
23
|
+
RenuoCliConfig.toggl_api_token
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.password
|
27
|
+
'api_token'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'active_resource'
|
2
|
+
|
3
|
+
module Toggl
|
4
|
+
class TimeEntry < ActiveResource::Base
|
5
|
+
self.site = 'https://www.toggl.com/api/v8/'
|
6
|
+
self.include_root_in_json = true
|
7
|
+
self.include_format_in_path = false
|
8
|
+
|
9
|
+
def self.user
|
10
|
+
RenuoCliConfig.toggl_api_token
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.password
|
14
|
+
'api_token'
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.current
|
18
|
+
data = get(:current)['data']
|
19
|
+
data ? new(data) : nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.start(params)
|
23
|
+
post(:start, {}, params.to_json)
|
24
|
+
end
|
25
|
+
|
26
|
+
def stop
|
27
|
+
put(:stop)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Toggl
|
2
|
+
class User < ActiveResource::Base
|
3
|
+
self.site = 'https://www.toggl.com/api/v8/'
|
4
|
+
self.include_root_in_json = true
|
5
|
+
self.include_format_in_path = false
|
6
|
+
|
7
|
+
def self.user
|
8
|
+
RenuoCliConfig.toggl_api_token
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.password
|
12
|
+
'api_token'
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.custom_method_collection_url(method_name, options)
|
16
|
+
prefix_options, query_options = split_options(options)
|
17
|
+
"#{prefix(prefix_options)}#{method_name}#{format_extension}#{query_string(query_options)}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.me
|
21
|
+
new(get(:me)['data'])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'active_resource'
|
2
|
+
|
3
|
+
module Toggl
|
4
|
+
class Workspace < ActiveResource::Base
|
5
|
+
self.site = 'https://www.toggl.com/api/v8/'
|
6
|
+
self.include_root_in_json = true
|
7
|
+
self.include_format_in_path = false
|
8
|
+
|
9
|
+
def self.user
|
10
|
+
RenuoCliConfig.toggl_api_token
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.password
|
14
|
+
'api_token'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'commander'
|
2
|
+
require 'csv'
|
3
|
+
require_relative './environments'
|
4
|
+
require_relative './fetch_emails'
|
5
|
+
require 'renuo/cli/app/toggl/workspace'
|
6
|
+
require 'renuo/cli/app/toggl/detail'
|
7
|
+
require 'renuo/cli/app/toggl/user'
|
8
|
+
require 'terminal-table'
|
9
|
+
require 'colorize'
|
10
|
+
|
11
|
+
class TogglRedmineComparator
|
12
|
+
class << self
|
13
|
+
def call(days_behind = 7)
|
14
|
+
report = {}
|
15
|
+
since_date = days_behind.days.before(Date.yesterday).strftime('%F')
|
16
|
+
until_date = Date.yesterday.strftime('%F')
|
17
|
+
extract_redmine(report, since_date, until_date)
|
18
|
+
extract_toggl(report, since_date, until_date)
|
19
|
+
report = report.sort.reverse.to_h
|
20
|
+
print_table(report)
|
21
|
+
report
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def print_table(report)
|
27
|
+
rows = []
|
28
|
+
report.each do |date, value|
|
29
|
+
rows << colorize_table_row(date, value)
|
30
|
+
rows << :separator
|
31
|
+
end
|
32
|
+
rows.pop
|
33
|
+
table = Terminal::Table.new headings: %w[Day Redmine Toggl].map(&:cyan), rows: rows,
|
34
|
+
style: { padding_left: 2, padding_right: 2,
|
35
|
+
border_x: '-'.blue, border_y: '|'.blue, border_i: '+'.blue }
|
36
|
+
puts table
|
37
|
+
end
|
38
|
+
|
39
|
+
def colorize_table_row(date, value)
|
40
|
+
printed_day = date.strftime('%F %a')
|
41
|
+
printed_redmine = to_time(value[:redmine])
|
42
|
+
printed_toggl = to_time(value[:toggl])
|
43
|
+
colorize_method = colorization_for_value(value)
|
44
|
+
[printed_day, printed_redmine, printed_toggl].map { |v| v.colorize(colorize_method) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def colorization_for_value(value)
|
48
|
+
if more_toggl?(value)
|
49
|
+
:red
|
50
|
+
elsif more_redmine?(value)
|
51
|
+
:default
|
52
|
+
else
|
53
|
+
:green
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def extract_redmine(report, since_date, _until_date)
|
58
|
+
encoded_body = perform_redmine_call(since_date)
|
59
|
+
csv = convert_redmine_csv(encoded_body)
|
60
|
+
csv.each do |date, entry|
|
61
|
+
report[Date.parse(date)] ||= default_value
|
62
|
+
report[Date.parse(date)][:redmine] = to_seconds(entry) if entry.present?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def convert_redmine_csv(encoded_body)
|
67
|
+
separated_csv_entries = CSV.parse(encoded_body, col_sep: ',')
|
68
|
+
keys = separated_csv_entries.shift[1..-2]
|
69
|
+
entries = separated_csv_entries.shift[1..-2]
|
70
|
+
keys.zip(entries)
|
71
|
+
end
|
72
|
+
|
73
|
+
def perform_redmine_call(since_date)
|
74
|
+
query = generate_redmine_query(since_date)
|
75
|
+
url = URI("https://redmine.renuo.ch/time_entries/report.csv?#{query}")
|
76
|
+
req = Net::HTTP::Get.new(url)
|
77
|
+
req['X-Redmine-API-Key'] = RenuoCliConfig.redmine_api_key
|
78
|
+
response = Net::HTTP.start(url.hostname, url.port, use_ssl: true) { |http| http.request(req) }
|
79
|
+
response.body.force_encoding('ISO-8859-1').encode('UTF-8')
|
80
|
+
end
|
81
|
+
|
82
|
+
def generate_redmine_query(since_date)
|
83
|
+
URI.encode_www_form(
|
84
|
+
[['utf8', '✓'], ['criteria[]', 'user'],
|
85
|
+
['f[]', 'spent_on'], ['f[]', 'user_id'],
|
86
|
+
['op[spent_on]', '>='], ['op[user_id]', '='],
|
87
|
+
['v[spent_on][]', since_date], ['v[user_id][]', 'me'],
|
88
|
+
['f[]', ''],
|
89
|
+
['c[]', 'project'], ['c[]', 'spent_on'], ['c[]', 'user'], ['c[]', 'activity'], ['c[]', 'issue'],
|
90
|
+
['c[]', 'comments'], ['c[]', 'hours'], %w[columns day], ['criteria[]', '']]
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
def extract_toggl(report, since_date, until_date)
|
95
|
+
user_id = Toggl::User.me.id
|
96
|
+
workspace_ids = Toggl::Workspace.all.map(&:id)
|
97
|
+
|
98
|
+
workspace_ids.each do |workspace_id|
|
99
|
+
time_entries = Toggl::Detail.where(since: since_date, until: until_date,
|
100
|
+
user_agent: 'renuo-cli', workspace_id: workspace_id, user_ids: user_id)
|
101
|
+
parse_toggl_entries(report, time_entries)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def parse_toggl_entries(report, time_entries)
|
106
|
+
time_entries
|
107
|
+
.reject { |te| te.end.nil? }
|
108
|
+
.group_by { |time_entry| Date.parse(time_entry.end) }
|
109
|
+
.each do |date, grouped_time_entries|
|
110
|
+
report[date] ||= default_value
|
111
|
+
report[date][:toggl] += grouped_time_entries.sum(&:dur)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def default_value
|
116
|
+
{ redmine: 0.0, toggl: 0.0 }
|
117
|
+
end
|
118
|
+
|
119
|
+
def to_time(value)
|
120
|
+
sec = value / 1000.0
|
121
|
+
min, _sec = sec.divmod(60.0)
|
122
|
+
hour, min = min.divmod(60.0)
|
123
|
+
format('%02d:%02d', hour, min)
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_seconds(value)
|
127
|
+
hours, minutes = value.to_d.divmod(1.0)
|
128
|
+
(hours * 60 * 60 * 1000) + (minutes * 60 * 60 * 1000)
|
129
|
+
end
|
130
|
+
|
131
|
+
def non_working_day?(value)
|
132
|
+
[value[:redmine], value[:toggl]].all? { |v| v == 0.0 }
|
133
|
+
end
|
134
|
+
|
135
|
+
BUFFER = 20_000
|
136
|
+
|
137
|
+
def more_toggl?(value)
|
138
|
+
(value[:toggl] - value[:redmine]) > BUFFER
|
139
|
+
end
|
140
|
+
|
141
|
+
def more_redmine?(value)
|
142
|
+
(value[:redmine] - value[:toggl]) > BUFFER
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'renuo/cli/app/redmine/issue'
|
3
|
+
require 'renuo/cli/app/toggl/time_entry'
|
4
|
+
|
5
|
+
class Work
|
6
|
+
ACTIONS = %w[start].freeze
|
7
|
+
|
8
|
+
def run(args)
|
9
|
+
ActiveResource::Base.logger = Logger.new(STDOUT)
|
10
|
+
@action, @project_name, @ticket_number = args
|
11
|
+
validate_action
|
12
|
+
validate_project_name
|
13
|
+
validate_ticket_number
|
14
|
+
start_feature_branch
|
15
|
+
update_redmine_ticket
|
16
|
+
start_toggl
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# TODO: I want to implement also the stop action.
|
22
|
+
def validate_action
|
23
|
+
abort('>> No action given. It must be start') unless ACTIONS.include? @action
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate_project_name
|
27
|
+
abort('>> No project name given.') unless @project_name
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate_ticket_number
|
31
|
+
abort('>> No ticket number given.') unless @ticket_number
|
32
|
+
issue = Redmine::Issue.find(@ticket_number)
|
33
|
+
open_statuses = Redmine::Issue::STATUSES.values_at(:to_start, :planned, :in_progress, :qa)
|
34
|
+
return if open_statuses.include?(issue.status.id)
|
35
|
+
|
36
|
+
system("open #{issue.html_url}")
|
37
|
+
abort('>> Ticket should be in an open status')
|
38
|
+
end
|
39
|
+
|
40
|
+
def start_feature_branch
|
41
|
+
project_folder = `autojump #{@project_name}`.strip
|
42
|
+
system("cd #{project_folder} && git stash && git checkout develop "\
|
43
|
+
"&& git pull && git flow feature start #{@ticket_number}")
|
44
|
+
end
|
45
|
+
|
46
|
+
def update_redmine_ticket
|
47
|
+
issue = Redmine::Issue.find(@ticket_number)
|
48
|
+
issue.status_id = Redmine::Issue::STATUSES[:in_progress]
|
49
|
+
issue.save
|
50
|
+
system("open #{issue.html_url}")
|
51
|
+
end
|
52
|
+
|
53
|
+
def start_toggl
|
54
|
+
current_time_entry = Toggl::TimeEntry.current
|
55
|
+
if current_time_entry.nil?
|
56
|
+
create_toggl_time_entry
|
57
|
+
elsif current_time_entry.description.nil?
|
58
|
+
update_toggl_time_entry(current_time_entry.id)
|
59
|
+
else
|
60
|
+
existing_toggl(current_time_entry)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def existing_toggl(current_time_entry)
|
65
|
+
say("A timer '#{current_time_entry.description}' was already running.")
|
66
|
+
if current_time_entry.description.to_i == @ticket_number.to_i
|
67
|
+
say('I will keep using it')
|
68
|
+
else
|
69
|
+
say('I stopped it and started a new time entry.')
|
70
|
+
stop_toggl_time_entry(current_time_entry.id)
|
71
|
+
create_toggl_time_entry
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def update_toggl_time_entry(time_entry_id)
|
76
|
+
say('A timer was already running but without a project assigned. I updated the current time entry.')
|
77
|
+
|
78
|
+
time_entry = Toggl::TimeEntry.find(time_entry_id)
|
79
|
+
time_entry.description = @ticket_number.to_s
|
80
|
+
time_entry.tags = [@project_name.to_s]
|
81
|
+
time_entry.created_with = 'curl'
|
82
|
+
time_entry.save
|
83
|
+
end
|
84
|
+
|
85
|
+
def create_toggl_time_entry
|
86
|
+
Toggl::TimeEntry.start(time_entry: { description: @ticket_number.to_s,
|
87
|
+
tags: [@project_name.to_s],
|
88
|
+
created_with: 'curl' })
|
89
|
+
end
|
90
|
+
|
91
|
+
def stop_toggl_time_entry(time_entry_id)
|
92
|
+
Toggl::TimeEntry.find(time_entry_id).stop
|
93
|
+
end
|
94
|
+
end
|
data/lib/renuo/cli/version.rb
CHANGED
data/renuo-cli.gemspec
CHANGED
@@ -17,14 +17,15 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.executables << 'renuo'
|
18
18
|
spec.require_paths = ['lib']
|
19
19
|
|
20
|
+
spec.add_dependency 'activeresource', '~> 5.1.0'
|
20
21
|
spec.add_dependency 'colorize', '~> 0'
|
21
22
|
spec.add_dependency 'commander', '~> 4.0'
|
22
23
|
spec.add_dependency 'gems', '~> 1.1'
|
23
24
|
spec.add_dependency 'redcarpet', '~> 3.0'
|
25
|
+
spec.add_dependency 'terminal-table'
|
24
26
|
|
25
27
|
spec.add_development_dependency 'aruba', '~> 0.14.5'
|
26
28
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
27
|
-
spec.add_development_dependency 'coveralls', '~> 0.8.9'
|
28
29
|
spec.add_development_dependency 'cucumber', '~> 3.1'
|
29
30
|
spec.add_development_dependency 'dotenv', '~> 2.7.2'
|
30
31
|
spec.add_development_dependency 'mdl', '~> 0.4.0'
|
@@ -32,7 +33,8 @@ Gem::Specification.new do |spec|
|
|
32
33
|
spec.add_development_dependency 'rake', '~> 10.0'
|
33
34
|
spec.add_development_dependency 'rspec', '~> 3.5'
|
34
35
|
spec.add_development_dependency 'rubocop', '0.55.0'
|
35
|
-
spec.add_development_dependency 'simplecov'
|
36
|
+
spec.add_development_dependency 'simplecov'
|
37
|
+
spec.add_development_dependency 'simplecov-console'
|
36
38
|
spec.add_development_dependency 'vcr', '~> 4.0.0'
|
37
39
|
spec.add_development_dependency 'webmock', '~> 3.5.1'
|
38
40
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: renuo-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Renuo AG
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activeresource
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 5.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 5.1.0
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: colorize
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,47 +81,47 @@ dependencies:
|
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '3.0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
84
|
+
name: terminal-table
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
72
86
|
requirements:
|
73
|
-
- - "
|
87
|
+
- - ">="
|
74
88
|
- !ruby/object:Gem::Version
|
75
|
-
version: 0
|
76
|
-
type: :
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
77
91
|
prerelease: false
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
79
93
|
requirements:
|
80
|
-
- - "
|
94
|
+
- - ">="
|
81
95
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
98
|
+
name: aruba
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
101
|
- - "~>"
|
88
102
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
103
|
+
version: 0.14.5
|
90
104
|
type: :development
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
108
|
- - "~>"
|
95
109
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
110
|
+
version: 0.14.5
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
112
|
+
name: bundler
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
115
|
- - "~>"
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version: 0
|
117
|
+
version: '2.0'
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0
|
124
|
+
version: '2.0'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: cucumber
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -210,16 +224,30 @@ dependencies:
|
|
210
224
|
name: simplecov
|
211
225
|
requirement: !ruby/object:Gem::Requirement
|
212
226
|
requirements:
|
213
|
-
- -
|
227
|
+
- - ">="
|
214
228
|
- !ruby/object:Gem::Version
|
215
|
-
version: 0
|
229
|
+
version: '0'
|
216
230
|
type: :development
|
217
231
|
prerelease: false
|
218
232
|
version_requirements: !ruby/object:Gem::Requirement
|
219
233
|
requirements:
|
220
|
-
- -
|
234
|
+
- - ">="
|
235
|
+
- !ruby/object:Gem::Version
|
236
|
+
version: '0'
|
237
|
+
- !ruby/object:Gem::Dependency
|
238
|
+
name: simplecov-console
|
239
|
+
requirement: !ruby/object:Gem::Requirement
|
240
|
+
requirements:
|
241
|
+
- - ">="
|
221
242
|
- !ruby/object:Gem::Version
|
222
|
-
version: 0
|
243
|
+
version: '0'
|
244
|
+
type: :development
|
245
|
+
prerelease: false
|
246
|
+
version_requirements: !ruby/object:Gem::Requirement
|
247
|
+
requirements:
|
248
|
+
- - ">="
|
249
|
+
- !ruby/object:Gem::Version
|
250
|
+
version: '0'
|
223
251
|
- !ruby/object:Gem::Dependency
|
224
252
|
name: vcr
|
225
253
|
requirement: !ruby/object:Gem::Requirement
|
@@ -257,14 +285,14 @@ executables:
|
|
257
285
|
extensions: []
|
258
286
|
extra_rdoc_files: []
|
259
287
|
files:
|
260
|
-
- ".coveralls.yml"
|
261
288
|
- ".editorconfig"
|
262
289
|
- ".gitignore"
|
263
290
|
- ".mdlrc"
|
264
291
|
- ".rspec"
|
265
292
|
- ".rubocop.yml"
|
266
293
|
- ".ruby-version"
|
267
|
-
- ".
|
294
|
+
- ".semaphore/master-deploy.yml"
|
295
|
+
- ".semaphore/semaphore.yml"
|
268
296
|
- CODE_OF_CONDUCT.md
|
269
297
|
- Gemfile
|
270
298
|
- LICENSE.txt
|
@@ -276,6 +304,7 @@ files:
|
|
276
304
|
- bin/run
|
277
305
|
- bin/setup
|
278
306
|
- lib/renuo/cli.rb
|
307
|
+
- lib/renuo/cli/app/configure_semaphore.rb
|
279
308
|
- lib/renuo/cli/app/configure_sentry.rb
|
280
309
|
- lib/renuo/cli/app/create_aws_project.rb
|
281
310
|
- lib/renuo/cli/app/create_heroku_app.rb
|
@@ -288,15 +317,26 @@ files:
|
|
288
317
|
- lib/renuo/cli/app/list_large_git_files.rb
|
289
318
|
- lib/renuo/cli/app/local_storage.rb
|
290
319
|
- lib/renuo/cli/app/name_display.rb
|
320
|
+
- lib/renuo/cli/app/redmine/csv_base_service.rb
|
321
|
+
- lib/renuo/cli/app/redmine/issue.rb
|
291
322
|
- lib/renuo/cli/app/release_project.rb
|
292
323
|
- lib/renuo/cli/app/release_xing.rb
|
293
324
|
- lib/renuo/cli/app/services/cloudfront_config_service.rb
|
294
325
|
- lib/renuo/cli/app/services/markdown_parser_service.rb
|
326
|
+
- lib/renuo/cli/app/services/renuo_cli_config.rb
|
295
327
|
- lib/renuo/cli/app/setup_uptimerobot.rb
|
328
|
+
- lib/renuo/cli/app/templates/semaphore-deploy.yml.erb
|
329
|
+
- lib/renuo/cli/app/templates/semaphore.yml.erb
|
330
|
+
- lib/renuo/cli/app/toggl/detail.rb
|
331
|
+
- lib/renuo/cli/app/toggl/time_entry.rb
|
332
|
+
- lib/renuo/cli/app/toggl/user.rb
|
333
|
+
- lib/renuo/cli/app/toggl/workspace.rb
|
334
|
+
- lib/renuo/cli/app/toggl_redmine_comparator.rb
|
296
335
|
- lib/renuo/cli/app/upgrade_laptop.rb
|
297
336
|
- lib/renuo/cli/app/upgrade_laptop/run_command.rb
|
298
337
|
- lib/renuo/cli/app/upgrade_laptop/upgrade_laptop_execution.rb
|
299
338
|
- lib/renuo/cli/app/upgrade_laptop/upgrade_mac_os.rb
|
339
|
+
- lib/renuo/cli/app/work.rb
|
300
340
|
- lib/renuo/cli/version.rb
|
301
341
|
- renuo-cli.gemspec
|
302
342
|
- vcr_cassettes/successful_uptimerobot_calls.yml
|
@@ -320,7 +360,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
320
360
|
- !ruby/object:Gem::Version
|
321
361
|
version: '0'
|
322
362
|
requirements: []
|
323
|
-
|
363
|
+
rubyforge_project:
|
364
|
+
rubygems_version: 2.6.14
|
324
365
|
signing_key:
|
325
366
|
specification_version: 4
|
326
367
|
summary: The Renuo CLI automates some common workflows.
|
data/.coveralls.yml
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
|