neetob-ud 0.1.0
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 +7 -0
- data/.editorconfig +10 -0
- data/.env +1 -0
- data/.rubocop.yml +596 -0
- data/.ruby-version +1 -0
- data/.semaphore/semaphore.yml +30 -0
- data/CHANGELOG.md +96 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +28 -0
- data/Gemfile.lock +250 -0
- data/LICENSE.txt +21 -0
- data/README.md +412 -0
- data/Rakefile +16 -0
- data/config/secrets.yml +0 -0
- data/data/branch-protection-rules.json +25 -0
- data/data/config-vars-audit.json +18 -0
- data/data/config-vars-list.json +1 -0
- data/data/github-labels.json +197 -0
- data/env.sample +1 -0
- data/exe/neetob +25 -0
- data/install.sh +21 -0
- data/lib/neetob/cli/base.rb +96 -0
- data/lib/neetob/cli/fetchorupdate_repos/execute.rb +55 -0
- data/lib/neetob/cli/github/auth.rb +134 -0
- data/lib/neetob/cli/github/base.rb +42 -0
- data/lib/neetob/cli/github/commands.rb +54 -0
- data/lib/neetob/cli/github/issues/commands.rb +51 -0
- data/lib/neetob/cli/github/issues/create.rb +42 -0
- data/lib/neetob/cli/github/issues/list.rb +94 -0
- data/lib/neetob/cli/github/labels/commands.rb +65 -0
- data/lib/neetob/cli/github/labels/delete.rb +46 -0
- data/lib/neetob/cli/github/labels/delete_all.rb +50 -0
- data/lib/neetob/cli/github/labels/list.rb +38 -0
- data/lib/neetob/cli/github/labels/show.rb +39 -0
- data/lib/neetob/cli/github/labels/update.rb +42 -0
- data/lib/neetob/cli/github/labels/upsert.rb +64 -0
- data/lib/neetob/cli/github/login.rb +16 -0
- data/lib/neetob/cli/github/make_pr/base.rb +72 -0
- data/lib/neetob/cli/github/make_pr/commands.rb +37 -0
- data/lib/neetob/cli/github/make_pr/compliance_fix.rb +49 -0
- data/lib/neetob/cli/github/make_pr/script.rb +55 -0
- data/lib/neetob/cli/github/protect_branch.rb +48 -0
- data/lib/neetob/cli/github/search.rb +38 -0
- data/lib/neetob/cli/heroku/access/add.rb +38 -0
- data/lib/neetob/cli/heroku/access/commands.rb +41 -0
- data/lib/neetob/cli/heroku/access/list.rb +36 -0
- data/lib/neetob/cli/heroku/access/remove.rb +38 -0
- data/lib/neetob/cli/heroku/commands.rb +28 -0
- data/lib/neetob/cli/heroku/config_vars/audit.rb +64 -0
- data/lib/neetob/cli/heroku/config_vars/base.rb +19 -0
- data/lib/neetob/cli/heroku/config_vars/commands.rb +49 -0
- data/lib/neetob/cli/heroku/config_vars/list.rb +56 -0
- data/lib/neetob/cli/heroku/config_vars/remove.rb +39 -0
- data/lib/neetob/cli/heroku/config_vars/upsert.rb +80 -0
- data/lib/neetob/cli/heroku/execute.rb +37 -0
- data/lib/neetob/cli/local/commands.rb +19 -0
- data/lib/neetob/cli/local/ls.rb +29 -0
- data/lib/neetob/cli/sub_command_base.rb +17 -0
- data/lib/neetob/cli/ui.rb +41 -0
- data/lib/neetob/cli/users/audit.rb +121 -0
- data/lib/neetob/cli/users/commands.rb +30 -0
- data/lib/neetob/cli/users/commits.rb +171 -0
- data/lib/neetob/cli.rb +42 -0
- data/lib/neetob/exception_handler.rb +58 -0
- data/lib/neetob/utils.rb +16 -0
- data/lib/neetob/version.rb +5 -0
- data/lib/neetob.rb +10 -0
- data/neetob.gemspec +50 -0
- data/overcommit.yml +43 -0
- data/scripts/delete_unused_assets.rb +67 -0
- metadata +187 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../base"
|
4
|
+
|
5
|
+
module Neetob
|
6
|
+
class CLI
|
7
|
+
module Heroku
|
8
|
+
module Access
|
9
|
+
class List < Base
|
10
|
+
attr_accessor :apps, :sandbox
|
11
|
+
|
12
|
+
def initialize(apps, sandbox = false)
|
13
|
+
super()
|
14
|
+
@apps = apps
|
15
|
+
@sandbox = sandbox
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
matching_apps = find_all_matching_apps(apps, :heroku, sandbox)
|
20
|
+
matching_apps.each do |app|
|
21
|
+
ui.info("\n Users for \"#{app}\" app\n")
|
22
|
+
users = `heroku access -a #{app}`
|
23
|
+
unless $?.success?
|
24
|
+
ui.error("There is a problem in accessing the app with name \"#{app}\" in your account.")
|
25
|
+
ui.error("Please check the specified app name and ensure you're authorized to view that app.")
|
26
|
+
next
|
27
|
+
end
|
28
|
+
|
29
|
+
ui.success(users)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../base"
|
4
|
+
|
5
|
+
module Neetob
|
6
|
+
class CLI
|
7
|
+
module Heroku
|
8
|
+
module Access
|
9
|
+
class Remove < Base
|
10
|
+
attr_accessor :apps, :users_to_be_removed, :sandbox
|
11
|
+
|
12
|
+
def initialize(apps, users_to_be_removed = [], sandbox = false)
|
13
|
+
super()
|
14
|
+
@apps = apps
|
15
|
+
@users_to_be_removed = users_to_be_removed
|
16
|
+
@sandbox = sandbox
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
matching_apps = find_all_matching_apps(apps, :heroku, sandbox)
|
21
|
+
matching_apps.each do |app|
|
22
|
+
`heroku access -a #{app}`
|
23
|
+
unless $?.success?
|
24
|
+
ui.error("There is a problem in accessing the app with name \"#{app}\" in your account.")
|
25
|
+
ui.error("Please check the specified app name and ensure you're authorized to view that app.")
|
26
|
+
next
|
27
|
+
end
|
28
|
+
|
29
|
+
users_to_be_removed.each do |user|
|
30
|
+
ui.info(`heroku access:remove #{user} -a #{app}`)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
require_relative "config_vars/commands"
|
5
|
+
require_relative "access/commands"
|
6
|
+
require_relative "execute"
|
7
|
+
|
8
|
+
module Neetob
|
9
|
+
class CLI
|
10
|
+
module Heroku
|
11
|
+
class Commands < Thor
|
12
|
+
desc "execute", "Run the given Heroku CLI command or Rails console command on Heroku apps"
|
13
|
+
option :command, type: :string, aliases: "-c", required: true, desc: "Command to run on Heroku apps"
|
14
|
+
option :rails, type: :boolean, aliases: "-r", default: false, desc: "Use this flag to run the given command in the Rails console"
|
15
|
+
option :apps, type: :array, aliases: "-a", required: true, desc: "Heroku app names. Can be matched using the '*' wildcard. Example: \"neeto*\" \"neeto-cal-web-staging\""
|
16
|
+
def execute
|
17
|
+
Execute.new(options[:apps], options[:command], options[:rails], options[:sandbox]).run
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "config_vars", "Interact with the config(env) variables on Heroku apps"
|
21
|
+
subcommand "config_vars", ConfigVars::Commands
|
22
|
+
|
23
|
+
desc "access", "Interact with the users of the Heroku apps"
|
24
|
+
subcommand "access", Access::Commands
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "terminal-table"
|
5
|
+
|
6
|
+
require_relative "base"
|
7
|
+
|
8
|
+
module Neetob
|
9
|
+
class CLI
|
10
|
+
module Heroku
|
11
|
+
module ConfigVars
|
12
|
+
class Audit < Base
|
13
|
+
attr_accessor :apps, :expected_config_vars_json_file_path, :sandbox
|
14
|
+
|
15
|
+
def initialize(apps, expected_config_vars_json_file_path = "", sandbox = false)
|
16
|
+
super()
|
17
|
+
@apps = apps
|
18
|
+
@expected_config_vars_json_file_path = expected_config_vars_json_file_path
|
19
|
+
@sandbox = sandbox
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
matching_apps = find_all_matching_apps(apps, :heroku, sandbox)
|
24
|
+
table_rows = []
|
25
|
+
expected_config = read_json_file(expected_config_vars_json_file_path || default_config_vars_json_file_path)
|
26
|
+
return unless expected_config
|
27
|
+
|
28
|
+
matching_apps.each do |app|
|
29
|
+
actual_config = `heroku config -a #{app} --json`
|
30
|
+
unless $?.success?
|
31
|
+
ui.error("There is a problem in accessing the app with name \"#{app}\" in your account.")
|
32
|
+
ui.error("Please check the specified app name and ensure you're authorized to view that app.")
|
33
|
+
next
|
34
|
+
end
|
35
|
+
|
36
|
+
actual_config_json = JSON.parse(actual_config)
|
37
|
+
table_rows.concat(compare_config_and_build_rows(app, expected_config, actual_config_json))
|
38
|
+
end
|
39
|
+
table = Terminal::Table.new headings: ["App", "Config var", "Expected", "Result"], rows: table_rows
|
40
|
+
ui.success(table)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def compare_config_and_build_rows(app, expected_config, actual_config)
|
46
|
+
expected_config.map do |key, val|
|
47
|
+
row = [app, key.to_s]
|
48
|
+
row << (value_set_dynamically_by_heroku?(val) ? "Heroku has dynamically set the value" : val.to_s)
|
49
|
+
row << (actual_config[key] == val ? "✅" : (actual_config[key] || "No such key"))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def value_set_dynamically_by_heroku?(value)
|
54
|
+
value == { "isDynamic" => true }
|
55
|
+
end
|
56
|
+
|
57
|
+
def default_config_vars_json_file_path
|
58
|
+
File.expand_path("../../../../../data/config-vars-audit.json", __dir__)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../base"
|
4
|
+
|
5
|
+
module Neetob
|
6
|
+
class CLI
|
7
|
+
module Heroku
|
8
|
+
module ConfigVars
|
9
|
+
class Base < CLI::Base
|
10
|
+
attr_accessor :client
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
super()
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
|
5
|
+
require_relative "list"
|
6
|
+
require_relative "audit"
|
7
|
+
require_relative "upsert"
|
8
|
+
require_relative "remove"
|
9
|
+
require_relative "../../sub_command_base"
|
10
|
+
|
11
|
+
module Neetob
|
12
|
+
class CLI
|
13
|
+
module Heroku
|
14
|
+
module ConfigVars
|
15
|
+
class Commands < SubCommandBase
|
16
|
+
desc "list", "List all the config variables in the Heroku apps"
|
17
|
+
option :apps, type: :array, aliases: :a, required: true, desc: "Heroku app names. Can be matched using the '*' wildcard. Example: \"neeto*\" \"neeto-cal-web-staging\""
|
18
|
+
option :keys, type: :array, desc: "Array of config vars that needs to be listed."
|
19
|
+
option :path, type: :string, desc: "The JSON file path which has config vars that needs to be listed"
|
20
|
+
def list
|
21
|
+
List.new(options[:apps], options[:keys], options[:path], options[:sandbox]).run
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "audit", "Verify whether config vars set in Heroku apps matches against the conditions specified in JSON file."
|
25
|
+
option :apps, type: :array, aliases: :a, required: true, desc: "Heroku app names. Can be matched using the '*' wildcard. Example: \"neeto*\" \"neeto-cal-web-staging\""
|
26
|
+
option :path, type: :string, desc: "The JSON file path from which config vars will be compared"
|
27
|
+
def audit
|
28
|
+
Audit.new(options[:apps], options[:path], options[:sandbox]).run
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "upsert", "Update and insert the config vars in Heroku apps"
|
32
|
+
option :apps, type: :array, aliases: :a, desc: "Heroku app names. Can be matched using the '*' wildcard. Example: \"neeto*\" \"neeto-cal-web-staging\""
|
33
|
+
option :path, type: :string, aliases: :p, desc: "The JSON file path from which config vars will be upserted"
|
34
|
+
option :path_with_project_keys, type: :string, desc: "The JSON file path with the project names as the key containing required config vars for each project."
|
35
|
+
def upsert
|
36
|
+
Upsert.new(options[:apps], options[:path], options[:path_with_project_keys], options[:sandbox]).run
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "remove", "Remove the config vars from Heroku apps"
|
40
|
+
option :apps, type: :array, aliases: :a, required: true, desc: "Heroku app names. Can be matched using the '*' wildcard. Example: \"neeto*\" \"neeto-cal-web-staging\""
|
41
|
+
option :keys, type: :array, required: true, desc: "Array of config vars to be removed."
|
42
|
+
def remove
|
43
|
+
Remove.new(options[:apps], options[:keys], options[:sandbox]).run
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Neetob
|
6
|
+
class CLI
|
7
|
+
module Heroku
|
8
|
+
module ConfigVars
|
9
|
+
class List < Base
|
10
|
+
attr_accessor :apps, :sandbox, :keys, :required_config_vars_file_path
|
11
|
+
|
12
|
+
def initialize(apps, keys = [], required_config_vars_file_path = "", sandbox = false)
|
13
|
+
super()
|
14
|
+
@apps = apps
|
15
|
+
@sandbox = sandbox
|
16
|
+
@keys = keys
|
17
|
+
@required_config_vars_file_path = required_config_vars_file_path
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
matching_apps = find_all_matching_apps(apps, :heroku, sandbox)
|
22
|
+
matching_apps.each do |app|
|
23
|
+
ui.info("\n Config of #{app}\n")
|
24
|
+
config = `heroku config -a #{app} --json`
|
25
|
+
unless $?.success?
|
26
|
+
ui.error("There is a problem in accessing the app with name \"#{app}\" in your account.")
|
27
|
+
ui.error("Please check the specified app name and ensure you're authorized to view that app.")
|
28
|
+
next
|
29
|
+
end
|
30
|
+
table = Terminal::Table.new headings: table_columns, rows: filter_config(config)
|
31
|
+
ui.success(table)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def table_columns
|
38
|
+
["Key", "Value"]
|
39
|
+
end
|
40
|
+
|
41
|
+
def filter_config(config)
|
42
|
+
parsed_config = JSON.parse(config)
|
43
|
+
if keys.nil? && required_config_vars_file_path.nil?
|
44
|
+
return parsed_config
|
45
|
+
end
|
46
|
+
|
47
|
+
required_config = keys || read_json_file(required_config_vars_file_path)
|
48
|
+
required_config.map do |key|
|
49
|
+
[key, parsed_config[key]]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Neetob
|
6
|
+
class CLI
|
7
|
+
module Heroku
|
8
|
+
module ConfigVars
|
9
|
+
class Remove < Base
|
10
|
+
attr_accessor :apps, :keys, :sandbox
|
11
|
+
|
12
|
+
def initialize(apps, keys = [], sandbox = false)
|
13
|
+
super()
|
14
|
+
@apps = apps
|
15
|
+
@keys = keys
|
16
|
+
@sandbox = sandbox
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
matching_apps = find_all_matching_apps(apps, :heroku, sandbox)
|
21
|
+
matching_apps.each do |app|
|
22
|
+
`heroku access -a #{app}`
|
23
|
+
|
24
|
+
unless $?.success?
|
25
|
+
ui.error("There is a problem in accessing the app with name \"#{app}\" in your account.")
|
26
|
+
ui.error("Please check the specified app name and ensure you're authorized to view that app.")
|
27
|
+
next
|
28
|
+
end
|
29
|
+
|
30
|
+
keys.each do |key|
|
31
|
+
`heroku config:unset #{key} -a #{app}`
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Neetob
|
6
|
+
class CLI
|
7
|
+
module Heroku
|
8
|
+
module ConfigVars
|
9
|
+
class Upsert < Base
|
10
|
+
attr_accessor :apps, :required_config_vars_json_file_path,
|
11
|
+
:required_config_vars_with_project_keys_json_file_path, :sandbox
|
12
|
+
|
13
|
+
def initialize(apps, required_config_vars_json_file_path,
|
14
|
+
required_config_vars_with_project_keys_json_file_path, sandbox = false)
|
15
|
+
super()
|
16
|
+
@apps = apps
|
17
|
+
@required_config_vars_json_file_path = required_config_vars_json_file_path
|
18
|
+
@required_config_vars_with_project_keys_json_file_path =
|
19
|
+
required_config_vars_with_project_keys_json_file_path
|
20
|
+
@sandbox = sandbox
|
21
|
+
end
|
22
|
+
|
23
|
+
def run
|
24
|
+
check_the_given_arguments
|
25
|
+
inform_about_current_working_mode(sandbox) if apps.nil?
|
26
|
+
apps_to_be_updated = apps.nil? ?
|
27
|
+
read_json_file(required_config_vars_with_project_keys_json_file_path) :
|
28
|
+
find_all_matching_apps(apps, :heroku, sandbox)
|
29
|
+
inform_about_default_config_vars_file
|
30
|
+
|
31
|
+
apps_to_be_updated.each do |app|
|
32
|
+
required_config = apps.nil? ? app[1] : read_json_file(required_config_vars_json_file_path || default_config_vars_upsert_file_path)
|
33
|
+
app = app[0] if apps.nil?
|
34
|
+
|
35
|
+
if apps.nil? && sandbox && app != "neeto-dummy"
|
36
|
+
ui.error("The \"#{app}\" app is not available in sandbox mode.")
|
37
|
+
next
|
38
|
+
end
|
39
|
+
|
40
|
+
upsert_config_variables(app, required_config)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def upsert_config_variables(app, vars)
|
47
|
+
`heroku access -a #{app}`
|
48
|
+
unless $?.success?
|
49
|
+
ui.error("There is a problem in accessing the app with name \"#{app}\" in your account.")
|
50
|
+
ui.error("Please check the specified app name and ensure you're authorized to view that app.")
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
vars.each do |key, val|
|
55
|
+
`heroku config:set #{key}='#{val}' -a #{app}`
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def check_the_given_arguments
|
60
|
+
if (!apps.nil? && !required_config_vars_with_project_keys_json_file_path.nil?) ||
|
61
|
+
(apps.nil? && required_config_vars_with_project_keys_json_file_path.nil?)
|
62
|
+
ui.error("Please provide either apps or path to the config file with project keys")
|
63
|
+
exit
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def default_config_vars_upsert_file_path
|
68
|
+
File.expand_path("../../../../../data/config-vars-upsert.json", __dir__)
|
69
|
+
end
|
70
|
+
|
71
|
+
def inform_about_default_config_vars_file
|
72
|
+
if !apps.nil? && required_config_vars_with_project_keys_json_file_path.nil? && required_config_vars_json_file_path.nil?
|
73
|
+
ui.info("Upserting config vars from the \"neetob/data/config-vars-upsert.json\" file")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../base"
|
4
|
+
|
5
|
+
module Neetob
|
6
|
+
class CLI
|
7
|
+
module Heroku
|
8
|
+
class Execute < Base
|
9
|
+
attr_accessor :apps, :command_to_execute, :should_run_in_rails_console, :sandbox
|
10
|
+
|
11
|
+
def initialize(apps, command_to_execute, should_run_in_rails_console = false, sandbox = false)
|
12
|
+
super()
|
13
|
+
@apps = apps
|
14
|
+
@command_to_execute = command_to_execute
|
15
|
+
@should_run_in_rails_console = should_run_in_rails_console
|
16
|
+
@sandbox = sandbox
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
matching_apps = find_all_matching_apps(apps, :heroku, sandbox)
|
21
|
+
rails_runner_command = "heroku run rails runner '#{command_to_execute}'"
|
22
|
+
heroku_command = should_run_in_rails_console ? rails_runner_command : command_to_execute
|
23
|
+
matching_apps.each do |app|
|
24
|
+
ui.info("\n Working on #{app}\n")
|
25
|
+
output = `#{heroku_command} -a #{app}`
|
26
|
+
unless $?.success?
|
27
|
+
ui.error("There is a problem in accessing the app with name \"#{app}\" in your account.")
|
28
|
+
ui.error("Please check the specified app name and ensure you're authorized to view that app.")
|
29
|
+
next
|
30
|
+
end
|
31
|
+
ui.success(output)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
require_relative "ls"
|
5
|
+
|
6
|
+
module Neetob
|
7
|
+
class CLI
|
8
|
+
module Local
|
9
|
+
class Commands < Thor
|
10
|
+
desc "ls", "List the files in local neeto repos"
|
11
|
+
option :apps, type: :array, aliases: "-a", required: true, desc: "Neeto app names. Can be matched using the '*' wildcard. Example: \"neeto*\" \"neeto-cal-web\""
|
12
|
+
option :dir, type: :string, aliases: "-d", desc: "Mention the directory you want to list"
|
13
|
+
def ls
|
14
|
+
Ls.new(options[:apps], options[:dir], options[:sandbox]).run
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../base"
|
4
|
+
|
5
|
+
module Neetob
|
6
|
+
class CLI
|
7
|
+
module Local
|
8
|
+
class Ls < Base
|
9
|
+
attr_accessor :sandbox, :apps, :dir
|
10
|
+
|
11
|
+
def initialize(apps, dir, sandbox = false)
|
12
|
+
super()
|
13
|
+
@apps = apps
|
14
|
+
@dir = dir
|
15
|
+
@sandbox = sandbox
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
matching_apps = find_all_matching_apps(apps, :github, sandbox, true)
|
20
|
+
matching_apps.each do |app|
|
21
|
+
app_name = app.split("/")[1]
|
22
|
+
ui.info("\nListing files from #{app_name}/#{dir}\n")
|
23
|
+
ui.info(`cd ./#{app_name} && ls #{dir}`)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
|
5
|
+
class SubCommandBase < Thor
|
6
|
+
def self.banner(command, namespace = nil, subcommand = false)
|
7
|
+
"#{basename} #{subcommand_prefix} #{command.usage}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.subcommand_prefix
|
11
|
+
self.name
|
12
|
+
.split("::")[2..-2]
|
13
|
+
.map { |name| name.gsub(%r{^[A-Z]}) { |match| match[0].downcase } }
|
14
|
+
.map { |name| name.gsub(%r{[A-Z]}) { |match| "-#{match[0].downcase}" } }
|
15
|
+
.join(" ")
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
4# frozen_string_literal: true
|
4
|
+
|
5
|
+
require "thor"
|
6
|
+
|
7
|
+
module Neetob
|
8
|
+
class CLI
|
9
|
+
class UI
|
10
|
+
attr_accessor :shell
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@shell = Thor::Base.shell.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def say(statement, color = Thor::Shell::Color::YELLOW)
|
17
|
+
shell.say(statement, color)
|
18
|
+
end
|
19
|
+
|
20
|
+
def ask(question, echo = true)
|
21
|
+
shell.ask(question, echo: echo)
|
22
|
+
end
|
23
|
+
|
24
|
+
def yes?(question)
|
25
|
+
shell.yes?(question)
|
26
|
+
end
|
27
|
+
|
28
|
+
def error(statement)
|
29
|
+
shell.say(statement, Thor::Shell::Color::RED)
|
30
|
+
end
|
31
|
+
|
32
|
+
def success(statement)
|
33
|
+
shell.say(statement, Thor::Shell::Color::GREEN)
|
34
|
+
end
|
35
|
+
|
36
|
+
def info(statement)
|
37
|
+
shell.say(statement)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../base"
|
4
|
+
|
5
|
+
module Neetob
|
6
|
+
class CLI
|
7
|
+
module Users
|
8
|
+
class Audit < Base
|
9
|
+
attr_accessor :sandbox
|
10
|
+
|
11
|
+
def initialize(sandbox = false)
|
12
|
+
super()
|
13
|
+
@sandbox = sandbox
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
users_data = users_for_all_available_apps
|
18
|
+
users = extract_values_from_user_data(users_data)
|
19
|
+
email_repos_map = create_email_repos_map(users)
|
20
|
+
unique_users = users.uniq { |user| [user[0], user[1]] }.sort
|
21
|
+
ui.info("\nUsers with multiple emails:")
|
22
|
+
find_users_with_multiple_emails(unique_users.transpose, email_repos_map)
|
23
|
+
ui.info("Users with emails having 3rd party domains:")
|
24
|
+
find_users_with_invalid_emails(unique_users.transpose, email_repos_map)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def users_for_all_available_apps
|
30
|
+
find_all_matching_apps(["*"], :github, sandbox, true).map do |app|
|
31
|
+
clone_repo_and_get_users(app).split("\n").map { |user| "#{user} #{app}" }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def extract_values_from_user_data(users)
|
36
|
+
users.flatten.map do |user|
|
37
|
+
values = user.strip.split(" ")[1..-1]
|
38
|
+
[values[0..-3].join(" "), clean_email(values[-2]), clean_repo_name(values[-1])]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def clone_repo_and_get_users(app)
|
43
|
+
app_name_without_org_suffix = app.split("/")[1]
|
44
|
+
`git -C ./#{app_name_without_org_suffix} shortlog -sne`
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_email_repos_map(users)
|
48
|
+
map = {}
|
49
|
+
users.each do |user|
|
50
|
+
email = user[1]
|
51
|
+
repo = user[2]
|
52
|
+
map[email] = [] unless map.key?(email)
|
53
|
+
map[email].push(repo)
|
54
|
+
end
|
55
|
+
map
|
56
|
+
end
|
57
|
+
|
58
|
+
def find_users_with_multiple_emails(users, email_repos_map)
|
59
|
+
user_emails = {}
|
60
|
+
users[0].each_with_index do |name, index|
|
61
|
+
email = users[1][index]
|
62
|
+
user_emails[name] = [] unless user_emails.key?(name)
|
63
|
+
user_emails[name].push(email)
|
64
|
+
end
|
65
|
+
user_with_multiple_emails = user_emails.filter { |_, val| val.length > 1 }
|
66
|
+
table_rows = create_rows_and_add_repos(user_with_multiple_emails, email_repos_map)
|
67
|
+
create_and_show_table(table_rows, table_columns)
|
68
|
+
end
|
69
|
+
|
70
|
+
def find_users_with_invalid_emails(users, email_repos_map)
|
71
|
+
user_with_invalid_emails = {}
|
72
|
+
users[1].each_with_index do |email, index|
|
73
|
+
name = users[0][index]
|
74
|
+
if invalid_email?(email)
|
75
|
+
user_with_invalid_emails[name] = [] unless user_with_invalid_emails.key?(name)
|
76
|
+
user_with_invalid_emails[name].push(email)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
table_rows = create_rows_and_add_repos(user_with_invalid_emails, email_repos_map)
|
80
|
+
create_and_show_table(table_rows, table_columns)
|
81
|
+
end
|
82
|
+
|
83
|
+
def table_columns
|
84
|
+
[:Name, :Email, :Repo]
|
85
|
+
end
|
86
|
+
|
87
|
+
def create_rows_and_add_repos(users, email_repos_map)
|
88
|
+
users.map do |name, emails|
|
89
|
+
repos = emails.map { |email| email_repos_map[email] }
|
90
|
+
[name, emails.join(", "), join_and_truncate_repos(repos)]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def create_and_show_table(data, column_names)
|
95
|
+
table = Terminal::Table.new headings: column_names, rows: data
|
96
|
+
ui.error(table)
|
97
|
+
end
|
98
|
+
|
99
|
+
def join_and_truncate_repos(repos)
|
100
|
+
repos.flatten.uniq.join(",").truncate(35)
|
101
|
+
end
|
102
|
+
|
103
|
+
def clean_email(email)
|
104
|
+
email.gsub(/<|>/, "")
|
105
|
+
end
|
106
|
+
|
107
|
+
def clean_repo_name(repo)
|
108
|
+
repo.gsub("bigbinary/", "")
|
109
|
+
end
|
110
|
+
|
111
|
+
def invalid_email?(email)
|
112
|
+
!allowed_email_domains.any? { |domain| email.downcase.include?(domain) }
|
113
|
+
end
|
114
|
+
|
115
|
+
def allowed_email_domains
|
116
|
+
["github", "gmail", "bigbinary"]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|