renuo-cli 1.5.0 → 1.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|
-
[](https://coveralls.io/github/renuo/renuo-cli?branch=master)
|
3
|
-
[](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
|
-
|