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.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +10 -0
  3. data/.env +1 -0
  4. data/.rubocop.yml +596 -0
  5. data/.ruby-version +1 -0
  6. data/.semaphore/semaphore.yml +30 -0
  7. data/CHANGELOG.md +96 -0
  8. data/CODE_OF_CONDUCT.md +84 -0
  9. data/Gemfile +28 -0
  10. data/Gemfile.lock +250 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +412 -0
  13. data/Rakefile +16 -0
  14. data/config/secrets.yml +0 -0
  15. data/data/branch-protection-rules.json +25 -0
  16. data/data/config-vars-audit.json +18 -0
  17. data/data/config-vars-list.json +1 -0
  18. data/data/github-labels.json +197 -0
  19. data/env.sample +1 -0
  20. data/exe/neetob +25 -0
  21. data/install.sh +21 -0
  22. data/lib/neetob/cli/base.rb +96 -0
  23. data/lib/neetob/cli/fetchorupdate_repos/execute.rb +55 -0
  24. data/lib/neetob/cli/github/auth.rb +134 -0
  25. data/lib/neetob/cli/github/base.rb +42 -0
  26. data/lib/neetob/cli/github/commands.rb +54 -0
  27. data/lib/neetob/cli/github/issues/commands.rb +51 -0
  28. data/lib/neetob/cli/github/issues/create.rb +42 -0
  29. data/lib/neetob/cli/github/issues/list.rb +94 -0
  30. data/lib/neetob/cli/github/labels/commands.rb +65 -0
  31. data/lib/neetob/cli/github/labels/delete.rb +46 -0
  32. data/lib/neetob/cli/github/labels/delete_all.rb +50 -0
  33. data/lib/neetob/cli/github/labels/list.rb +38 -0
  34. data/lib/neetob/cli/github/labels/show.rb +39 -0
  35. data/lib/neetob/cli/github/labels/update.rb +42 -0
  36. data/lib/neetob/cli/github/labels/upsert.rb +64 -0
  37. data/lib/neetob/cli/github/login.rb +16 -0
  38. data/lib/neetob/cli/github/make_pr/base.rb +72 -0
  39. data/lib/neetob/cli/github/make_pr/commands.rb +37 -0
  40. data/lib/neetob/cli/github/make_pr/compliance_fix.rb +49 -0
  41. data/lib/neetob/cli/github/make_pr/script.rb +55 -0
  42. data/lib/neetob/cli/github/protect_branch.rb +48 -0
  43. data/lib/neetob/cli/github/search.rb +38 -0
  44. data/lib/neetob/cli/heroku/access/add.rb +38 -0
  45. data/lib/neetob/cli/heroku/access/commands.rb +41 -0
  46. data/lib/neetob/cli/heroku/access/list.rb +36 -0
  47. data/lib/neetob/cli/heroku/access/remove.rb +38 -0
  48. data/lib/neetob/cli/heroku/commands.rb +28 -0
  49. data/lib/neetob/cli/heroku/config_vars/audit.rb +64 -0
  50. data/lib/neetob/cli/heroku/config_vars/base.rb +19 -0
  51. data/lib/neetob/cli/heroku/config_vars/commands.rb +49 -0
  52. data/lib/neetob/cli/heroku/config_vars/list.rb +56 -0
  53. data/lib/neetob/cli/heroku/config_vars/remove.rb +39 -0
  54. data/lib/neetob/cli/heroku/config_vars/upsert.rb +80 -0
  55. data/lib/neetob/cli/heroku/execute.rb +37 -0
  56. data/lib/neetob/cli/local/commands.rb +19 -0
  57. data/lib/neetob/cli/local/ls.rb +29 -0
  58. data/lib/neetob/cli/sub_command_base.rb +17 -0
  59. data/lib/neetob/cli/ui.rb +41 -0
  60. data/lib/neetob/cli/users/audit.rb +121 -0
  61. data/lib/neetob/cli/users/commands.rb +30 -0
  62. data/lib/neetob/cli/users/commits.rb +171 -0
  63. data/lib/neetob/cli.rb +42 -0
  64. data/lib/neetob/exception_handler.rb +58 -0
  65. data/lib/neetob/utils.rb +16 -0
  66. data/lib/neetob/version.rb +5 -0
  67. data/lib/neetob.rb +10 -0
  68. data/neetob.gemspec +50 -0
  69. data/overcommit.yml +43 -0
  70. data/scripts/delete_unused_assets.rb +67 -0
  71. metadata +187 -0
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ require_relative "../base"
6
+
7
+ module Neetob
8
+ class CLI
9
+ module Github
10
+ module Labels
11
+ class Delete < Base
12
+ attr_accessor :apps, :sandbox, :labels, :all_neeto_repos
13
+
14
+ def initialize(apps, labels, sandbox = false, all_neeto_repos = false)
15
+ super()
16
+ @labels = labels
17
+ @apps = apps
18
+ @sandbox = sandbox
19
+ @all_neeto_repos = all_neeto_repos
20
+ end
21
+
22
+ def run
23
+ check_for_apps_and_all_neeto_repos_option(apps, all_neeto_repos)
24
+ matching_apps = find_all_matching_apps(apps, :github, sandbox, false, all_neeto_repos)
25
+ matching_apps.each do |app|
26
+ ui.info("\n Deleting labels from #{app} repo \n")
27
+ labels.each do |label|
28
+ delete_label(app, label)
29
+ end
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def delete_label(app, label)
36
+ if client.delete_label!(app, label)
37
+ ui.success("The \"#{label}\" label deleted successfully")
38
+ else
39
+ ui.error("The \"#{label}\" label can't be deleted. Please check and try again")
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ require_relative "../base"
6
+
7
+ module Neetob
8
+ class CLI
9
+ module Github
10
+ module Labels
11
+ class DeleteAll < Base
12
+ attr_accessor :apps, :sandbox, :all_neeto_repos
13
+
14
+ def initialize(apps, sandbox = false, all_neeto_repos = false)
15
+ super()
16
+ @apps = apps
17
+ @sandbox = sandbox
18
+ @all_neeto_repos = all_neeto_repos
19
+ end
20
+
21
+ def run
22
+ check_for_apps_and_all_neeto_repos_option(apps, all_neeto_repos)
23
+ matching_apps = find_all_matching_apps(apps, :github, sandbox, false, all_neeto_repos)
24
+ matching_apps.each do |app|
25
+ ui.info("\n Working on #{app} repo \n")
26
+ begin
27
+ labels = client.labels(app)
28
+ labels.each do |label|
29
+ delete_label(app, label)
30
+ end
31
+ rescue StandardError => e
32
+ ExceptionHandler.new(e).process
33
+ end
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def delete_label(app, label_details)
40
+ if client.delete_label!(app, label_details[:name])
41
+ ui.success("The \"#{label_details[:name]}\" label deleted successfully")
42
+ else
43
+ ui.error("The \"#{label_details[:name]}\" label can't be deleted. Please try again")
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ require_relative "../base"
6
+
7
+ module Neetob
8
+ class CLI
9
+ module Github
10
+ module Labels
11
+ class List < Base
12
+ attr_accessor :apps, :sandbox, :all_neeto_repos
13
+
14
+ def initialize(apps, sandbox = false, all_neeto_repos = false)
15
+ super()
16
+ @apps = apps
17
+ @sandbox = sandbox
18
+ @all_neeto_repos = all_neeto_repos
19
+ end
20
+
21
+ def run
22
+ check_for_apps_and_all_neeto_repos_option(apps, all_neeto_repos)
23
+ matching_apps = find_all_matching_apps(apps, :github, sandbox, false, all_neeto_repos)
24
+ matching_apps.each do |app|
25
+ ui.info("\n Labels of #{app} \n")
26
+ begin
27
+ labels = client.labels(app)
28
+ ui.success(labels)
29
+ rescue StandardError => e
30
+ ExceptionHandler.new(e).process
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ require_relative "../base"
6
+
7
+ module Neetob
8
+ class CLI
9
+ module Github
10
+ module Labels
11
+ class Show < Base
12
+ attr_accessor :apps, :label_name, :sandbox, :all_neeto_repos
13
+
14
+ def initialize(apps, label_name, sandbox = false, all_neeto_repos = false)
15
+ super()
16
+ @apps = apps
17
+ @label_name = label_name
18
+ @sandbox = sandbox
19
+ @all_neeto_repos = all_neeto_repos
20
+ end
21
+
22
+ def run
23
+ check_for_apps_and_all_neeto_repos_option(apps, all_neeto_repos)
24
+ matching_apps = find_all_matching_apps(apps, :github, sandbox, false, all_neeto_repos)
25
+ matching_apps.each do |app|
26
+ ui.info("\n \"#{label_name}\" label details from #{app} \n")
27
+ begin
28
+ label_details = client.label(app, label_name)
29
+ ui.success(label_details.inspect)
30
+ rescue StandardError => e
31
+ ExceptionHandler.new(e).process
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ require_relative "../base"
6
+
7
+ module Neetob
8
+ class CLI
9
+ module Github
10
+ module Labels
11
+ class Update < Base
12
+ attr_accessor :apps, :sandbox, :old_name, :new_name, :all_neeto_repos
13
+
14
+ def initialize(apps, old_name, new_name, sandbox = false, all_neeto_repos = false)
15
+ super()
16
+ @apps = apps
17
+ @sandbox = sandbox
18
+ @old_name = old_name
19
+ @new_name = new_name
20
+ @all_neeto_repos = all_neeto_repos
21
+ end
22
+
23
+ def run
24
+ check_for_apps_and_all_neeto_repos_option(apps, all_neeto_repos)
25
+ matching_apps = find_all_matching_apps(apps, :github, sandbox, false, all_neeto_repos)
26
+ matching_apps.each do |app|
27
+ ui.info("\n Updating label for #{app} repo \n")
28
+ update_label!(app, old_name, new_name)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def update_label!(app, old_name, new_name)
35
+ client.update_label(app, old_name, { name: new_name })
36
+ ui.success("Label \"#{old_name}\" updated to \"#{new_name}\" successfully")
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ require_relative "../base"
6
+
7
+ module Neetob
8
+ class CLI
9
+ module Github
10
+ module Labels
11
+ class Upsert < Base
12
+ attr_accessor :apps, :required_labels_json_file_path, :sandbox, :all_neeto_repos
13
+
14
+ def initialize(apps, required_labels_json_file_path = "", sandbox = false, all_neeto_repos = false)
15
+ super()
16
+ @apps = apps
17
+ @required_labels_json_file_path = required_labels_json_file_path
18
+ @sandbox = sandbox
19
+ @all_neeto_repos = all_neeto_repos
20
+ end
21
+
22
+ def run
23
+ check_for_apps_and_all_neeto_repos_option(apps, all_neeto_repos)
24
+ matching_apps = find_all_matching_apps(apps, :github, sandbox, false, all_neeto_repos)
25
+ inform_about_default_labels_file
26
+ matching_apps.each do |app|
27
+ ui.info("\n Working on #{app} repo \n")
28
+ begin
29
+ required_labels = read_json_file(required_labels_json_file_path || default_labels_file_path)
30
+ required_labels.each do |label|
31
+ create_or_update_label(app, label)
32
+ end
33
+ rescue StandardError => e
34
+ ExceptionHandler.new(e).process
35
+ end
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def create_or_update_label(app, label_details)
42
+ begin
43
+ client.update_label(app, label_details["name"], label_details)
44
+ ui.success("Label \"#{label_details["name"]}\" updated successfully")
45
+ rescue Octokit::NotFound
46
+ client.add_label(app, label_details["name"], label_details["color"], label_details)
47
+ ui.success("Label \"#{label_details["name"]}\" created successfully")
48
+ end
49
+ end
50
+
51
+ def default_labels_file_path
52
+ File.expand_path("../../../../../data/github-labels.json", __dir__)
53
+ end
54
+
55
+ def inform_about_default_labels_file
56
+ if required_labels_json_file_path.nil?
57
+ ui.info("Upserting labels from the \"neetob/data/github-labels.json\" file")
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Neetob
6
+ class CLI
7
+ module Github
8
+ class Login < Base
9
+ def initialize
10
+ super()
11
+ Auth.new(**read_and_parse_auth_params_from_env).start_oauth2_device_flow
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../base"
4
+
5
+ module Neetob
6
+ class CLI
7
+ module Github
8
+ module MakePr
9
+ class Base < Github::Base
10
+ BRANCH_NAME = "neeto_compliance"
11
+ PR_TITLE = "Neeto Compliance"
12
+ attr_accessor :branch_name, :pr_title
13
+
14
+ def initialize(pr_title = PR_TITLE, branch_name = BRANCH_NAME)
15
+ super()
16
+ @branch_name = branch_name || BRANCH_NAME
17
+ @pr_title = pr_title || PR_TITLE
18
+ end
19
+
20
+ private
21
+
22
+ def delete_and_create_temp_neetob_dir
23
+ `rm -rf /tmp/neetob`
24
+ `mkdir /tmp/neetob`
25
+ end
26
+
27
+ def app_name_without_org_suffix(app)
28
+ app.split("/").last
29
+ end
30
+
31
+ def clone_app_in_tmp_dir(app)
32
+ `git clone --quiet git@github.com:#{app}.git /tmp/neetob/#{app_name_without_org_suffix(app)}`
33
+ end
34
+
35
+ def add_commmit_and_push_changes(app)
36
+ `#{cd_to_app_in_tmp_dir(app)} && git add . && git commit -m "#{pr_title}" && git push -u origin #{branch_name} --force`
37
+ end
38
+
39
+ def delete_local_feature_branch(app)
40
+ `#{cd_to_app_in_tmp_dir(app)} && git checkout main && git branch -D #{branch_name}`
41
+ end
42
+
43
+ def checkout_to_new_branch(app)
44
+ `#{cd_to_app_in_tmp_dir(app)} && git checkout -b #{branch_name}`
45
+ end
46
+
47
+ def checkout_to_feature_branch(app)
48
+ `#{cd_to_app_in_tmp_dir(app)} && git checkout #{branch_name}`
49
+ end
50
+
51
+ def delete_remote_feature_branch(app)
52
+ `#{cd_to_app_in_tmp_dir(app)} && git push origin --delete #{branch_name}`
53
+ end
54
+
55
+ def check_and_delete_remote_branch(app)
56
+ checkout_to_feature_branch(app)
57
+ if $?.success?
58
+ ui.info("Remote branch found with the name \"#{branch_name}\"")
59
+ delete_remote_feature_branch(app)
60
+ delete_local_feature_branch(app)
61
+ end
62
+ checkout_to_new_branch(app)
63
+ end
64
+
65
+ def cd_to_app_in_tmp_dir(app)
66
+ "cd /tmp/neetob/#{app_name_without_org_suffix(app)}"
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ require_relative "compliance_fix"
6
+ require_relative "script"
7
+ require_relative "../../sub_command_base"
8
+
9
+ module Neetob
10
+ class CLI
11
+ module Github
12
+ module MakePr
13
+ class Commands < SubCommandBase
14
+ class_option :apps,
15
+ {
16
+ type: :array, aliases: "-a", default: ["*"],
17
+ desc: "Github app names. Can be matched using the '*' wildcard. Example: \"neeto*\" \"neeto-cal-web\""
18
+ }
19
+
20
+ desc "compliance-fix", "Create PRs for fixing neeto compliance in all products"
21
+ def compliance_fix
22
+ ComplianceFix.new(options[:apps], options[:sandbox]).run
23
+ end
24
+
25
+ desc "script", "Create PRs after running the given script for each product."
26
+ option :path, type: :string, aliases: "-p",
27
+ desc: "Path to UNIX executable script which will be run for each product", required: true
28
+ option :title, type: :string, aliases: "-t", desc: "Title for the PR"
29
+ option :branch, type: :string, aliases: "-b", desc: "Feature branch name for the PR"
30
+ def script
31
+ Script.new(options[:apps], options[:path], options[:title], options[:branch], options[:sandbox]).run
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ require_relative "base"
6
+
7
+ module Neetob
8
+ class CLI
9
+ module Github
10
+ module MakePr
11
+ class ComplianceFix < Base
12
+ attr_accessor :apps, :sandbox
13
+
14
+ def initialize(apps, sandbox = false)
15
+ super()
16
+ @apps = apps
17
+ @sandbox = sandbox
18
+ end
19
+
20
+ def run
21
+ matching_apps = find_all_matching_apps(apps, :github, sandbox)
22
+ delete_and_create_temp_neetob_dir
23
+ matching_apps.each do |app|
24
+ ui.info("\n Working on #{app} \n")
25
+ begin
26
+ clone_app_in_tmp_dir(app)
27
+ check_and_delete_remote_branch(app)
28
+ bundle_install(app)
29
+ ui.info(add_commmit_and_push_changes(app))
30
+ delete_local_feature_branch(app)
31
+ res = client.create_pull_request(app, "main", BRANCH_NAME, PR_TITLE)
32
+ ui.success("PR created in \"#{app}\" project successfully.")
33
+ rescue StandardError => e
34
+ ExceptionHandler.new(e).process
35
+ end
36
+ end
37
+ `rm -rf /tmp/neetob`
38
+ end
39
+
40
+ private
41
+
42
+ def bundle_install(app)
43
+ `#{cd_to_app_in_tmp_dir(app)} && bundle`
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ require_relative "base"
6
+
7
+ module Neetob
8
+ class CLI
9
+ module Github
10
+ module MakePr
11
+ class Script < Base
12
+ attr_accessor :apps, :sandbox, :path_to_the_script_file
13
+
14
+ def initialize(apps, path_to_the_script_file, pr_title, branch_name, sandbox = false)
15
+ super(pr_title, branch_name)
16
+ @apps = apps
17
+ @sandbox = sandbox
18
+ @path_to_the_script_file = path_to_the_script_file
19
+ end
20
+
21
+ def run
22
+ matching_apps = find_all_matching_apps(apps, :github, sandbox)
23
+ delete_and_create_temp_neetob_dir
24
+ matching_apps.each do |app|
25
+ ui.info("\n Working on #{app} \n")
26
+ begin
27
+ clone_app_in_tmp_dir(app)
28
+ check_and_delete_remote_branch(app)
29
+ update_script_file_permissions
30
+ execute_script(app)
31
+ ui.info(add_commmit_and_push_changes(app))
32
+ delete_local_feature_branch(app)
33
+ res = client.create_pull_request(app, "main", branch_name, pr_title)
34
+ ui.success("PR created in \"#{app}\" project successfully.")
35
+ rescue StandardError => e
36
+ ExceptionHandler.new(e).process
37
+ end
38
+ end
39
+ `rm -rf /tmp/neetob`
40
+ end
41
+
42
+ private
43
+
44
+ def update_script_file_permissions
45
+ `chmod +x #{path_to_the_script_file}`
46
+ end
47
+
48
+ def execute_script(app)
49
+ `#{cd_to_app_in_tmp_dir(app)} && #{path_to_the_script_file}`
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Neetob
6
+ class CLI
7
+ module Github
8
+ class ProtectBranch < Base
9
+ attr_accessor :branch_name, :required_rules_json_file_path, :apps, :sandbox, :all_neeto_repos
10
+
11
+ def initialize(branch_name, apps, required_rules_json_file_path = "", sandbox = false, all_neeto_repos = false)
12
+ super()
13
+ @branch_name = branch_name
14
+ @required_rules_json_file_path = required_rules_json_file_path
15
+ @apps = apps
16
+ @sandbox = sandbox
17
+ @all_neeto_repos = all_neeto_repos
18
+ end
19
+
20
+ def run
21
+ check_for_apps_and_all_neeto_repos_option(apps, all_neeto_repos)
22
+ matching_apps = find_all_matching_apps(apps, :github, sandbox, false, all_neeto_repos)
23
+ inform_about_default_rules_file
24
+ matching_apps.each do |app|
25
+ ui.info("\n Working on \"#{app}\" repo")
26
+ ui.info(" Updating \"#{branch_name}\" branch protection rules")
27
+ rules = read_json_file(required_rules_json_file_path || default_rules_file_path)
28
+ rules_with_symbol_keys = rules.transform_keys(&:to_sym)
29
+ client.protect_branch(app, branch_name, rules_with_symbol_keys)
30
+ ui.success("Branch protection rules updated successfully")
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def default_rules_file_path
37
+ File.expand_path("../../../../data/branch-protection-rules.json", __dir__)
38
+ end
39
+
40
+ def inform_about_default_rules_file
41
+ if required_rules_json_file_path.nil?
42
+ ui.info("Updating protection rules from the \"neetob/data/branch-protection-rules.json\" file")
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Neetob
6
+ class CLI
7
+ module Github
8
+ class Search < Base
9
+ attr_accessor :apps, :key_to_search, :search_file_path, :sandbox
10
+
11
+ def initialize(apps, key_to_search, search_file_path, sandbox = false)
12
+ super()
13
+ @apps = apps
14
+ @key_to_search = key_to_search
15
+ @search_file_path = search_file_path
16
+ @sandbox = sandbox
17
+ end
18
+
19
+ def run
20
+ matching_apps = find_all_matching_apps(apps, :github, sandbox)
21
+ matching_apps.each do |app|
22
+ begin
23
+ ui.info("\n Searching in \"#{app}/#{search_file_path}\" for \"#{key_to_search}\"\n")
24
+ content = Base64.decode64(client.contents(app, path: search_file_path).content)
25
+ ui.error("Keyword not found") and next unless content.include? key_to_search
26
+
27
+ content.each_line do |line|
28
+ ui.success(line) if line.include?(key_to_search)
29
+ end
30
+ rescue StandardError => e
31
+ ExceptionHandler.new(e).process
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ 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 Add < Base
10
+ attr_accessor :apps, :new_users, :sandbox
11
+
12
+ def initialize(apps, new_users = [], sandbox = false)
13
+ super()
14
+ @apps = apps
15
+ @new_users = new_users
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
+ new_users.each do |user|
30
+ ui.info(`heroku access:add #{user} -a #{app}`)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ require_relative "list"
6
+ require_relative "add"
7
+ require_relative "remove"
8
+ require_relative "../../sub_command_base"
9
+
10
+ module Neetob
11
+ class CLI
12
+ module Heroku
13
+ module Access
14
+ class Commands < SubCommandBase
15
+ class_option :apps,
16
+ {
17
+ type: :array, aliases: "-a", required: true,
18
+ desc: "Heroku app names. Can be matched using the '*' wildcard. Example: \"neeto*\" \"neeto-cal-web-staging\""
19
+ }
20
+
21
+ desc "list", "List all the users of the Heroku apps"
22
+ def list
23
+ List.new(options[:apps], options[:sandbox]).run
24
+ end
25
+
26
+ desc "add", "Add new users to the Heroku apps"
27
+ option :users, type: :array, required: true, desc: "Users' emails that need to be added to Heroku apps"
28
+ def add
29
+ Add.new(options[:apps], options[:users], options[:sandbox]).run
30
+ end
31
+
32
+ desc "remove", "Remove the users from the Heroku apps"
33
+ option :users, type: :array, required: true, desc: "Users' emails that need to be removed from the Heroku apps"
34
+ def remove
35
+ Remove.new(options[:apps], options[:users], options[:sandbox]).run
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end