neetob 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +31 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +26 -0
- data/Gemfile.lock +249 -0
- data/LICENSE.txt +21 -0
- data/README.md +381 -0
- data/Rakefile +16 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/github_access.rb +29 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/neeto_apps.rb +35 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/neeto_commons.rb +16 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/runner.rb +35 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/skippable.rb +19 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/sync_neeto_commons/sync_bin.rb +32 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/sync_neeto_commons/sync_formatters.rb +35 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/sync_neeto_commons/sync_husky.rb +33 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/sync_neeto_commons/sync_misc.rb +36 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/sync_neeto_commons/sync_test_support.rb +38 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/sync_neeto_commons.rb +36 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/auto_update_prs_with_latest_master_verifier.rb +25 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/base.rb +72 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/bundler_version_verifier.rb +53 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/circleci_config_verifier.rb +25 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/common_gemfile_verifier.rb +25 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/common_initializers_verifier.rb +25 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/cypress_config_verifier.rb +46 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/cypress_plugins_index_verifier.rb +25 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/docker_file_dev_verifier.rb +25 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/environment_config_verifier.rb +38 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/gem_version_verifier.rb +38 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/gems_verifier_base.rb +34 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/gitignore_file_verifier.rb +39 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/jsconfig_verifier.rb +100 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/neeto_auth_gems_verifier.rb +20 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/neeto_commons_sync_verifier.rb +42 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/neeto_gems_version_verifier.rb +24 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/newrelic_verifier.rb +25 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/node_version_verifier.rb +63 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/package_dependencies_version_verifier.rb +62 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/package_json_verifier.rb +39 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/roles_verifier.rb +22 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/ruby_version_verifier.rb +25 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/semaphoreci_config_verifier.rb +162 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/sidekiq_queues_verifier.rb +34 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/simplecov_config_verifier.rb +28 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/sitemap_config_verifier.rb +29 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/slugignore_file_verifier.rb +25 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/sync_neeto_commons_verifier/bin_files_verifier.rb +29 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/sync_neeto_commons_verifier/formatter_files_verifier.rb +29 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/sync_neeto_commons_verifier/husky_files_verifier.rb +29 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/sync_neeto_commons_verifier/misc_files_verifier.rb +29 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/sync_neeto_commons_verifier/test_support_files_verifier.rb +28 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/sync_neeto_commons_verifier.rb +31 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/webpack_configuration_verifier.rb +44 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers/webpacker_config_verifier.rb +29 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/verifiers_list.rb +61 -0
- data/Users/chiragshah/Workspace/bigbinary/neeto/neetob/neeto_compliance/lib/neeto_compliance/version.rb +5 -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/config-vars-upsert.json +3 -0
- data/data/github-labels.json +192 -0
- data/env.sample +1 -0
- data/exe/neetob +25 -0
- data/install.sh +21 -0
- data/lib/neetob/cli/base.rb +85 -0
- data/lib/neetob/cli/fetchorupdate_repos/execute.rb +53 -0
- data/lib/neetob/cli/github/auth.rb +134 -0
- data/lib/neetob/cli/github/base.rb +35 -0
- data/lib/neetob/cli/github/commands.rb +50 -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 +62 -0
- data/lib/neetob/cli/github/labels/delete.rb +44 -0
- data/lib/neetob/cli/github/labels/delete_all.rb +48 -0
- data/lib/neetob/cli/github/labels/list.rb +36 -0
- data/lib/neetob/cli/github/labels/show.rb +37 -0
- data/lib/neetob/cli/github/labels/update.rb +40 -0
- data/lib/neetob/cli/github/labels/upsert.rb +62 -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 +46 -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 +28 -0
- data/lib/neetob/cli/users/commits.rb +125 -0
- data/lib/neetob/cli.rb +40 -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/overcommit.yml +43 -0
- data/scripts/delete_unused_assets.rb +67 -0
- metadata +235 -0
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../ui"
|
4
|
+
require "net/http"
|
5
|
+
require "uri"
|
6
|
+
require "json"
|
7
|
+
require "launchy"
|
8
|
+
require "fileutils"
|
9
|
+
|
10
|
+
module Neetob
|
11
|
+
class CLI
|
12
|
+
module Github
|
13
|
+
class Auth
|
14
|
+
attr_accessor :client_id, :grant_type, :uris, :provider, :scope, :access_token, :ui
|
15
|
+
|
16
|
+
def initialize(client_id:, grant_type:, auth_uris:, provider:, scope:)
|
17
|
+
@client_id = client_id
|
18
|
+
@grant_type = grant_type
|
19
|
+
@uris = auth_uris
|
20
|
+
@provider = provider
|
21
|
+
@scope = scope
|
22
|
+
@access_token = retrieve_persisted_token
|
23
|
+
@ui = CLI::UI.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def token_persisted?
|
27
|
+
access_token_present?
|
28
|
+
end
|
29
|
+
|
30
|
+
def open_url_in_browser!(url)
|
31
|
+
Launchy.open(url) do |exception|
|
32
|
+
raise(StandardError, "Attempted to open #{url} in browser and failed because #{exception}.")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def start_oauth2_device_flow
|
37
|
+
auth_data = request_authorization
|
38
|
+
show_user_code(auth_data[:user_code])
|
39
|
+
open_url_in_browser!(auth_data[:verification_uri])
|
40
|
+
poll_for_token(auth_data)
|
41
|
+
end
|
42
|
+
|
43
|
+
def request_authorization
|
44
|
+
post(uris["auth_req"], params: { client_id: client_id, scope: scope })
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def show_user_code(code)
|
50
|
+
ui.say("You'll be redirected to the browser in 5 secs. Enter the following code in the browser:")
|
51
|
+
ui.success(code)
|
52
|
+
sleep 5
|
53
|
+
end
|
54
|
+
|
55
|
+
def tmp_token_path(provider)
|
56
|
+
"/tmp/neetob_#{provider}_token"
|
57
|
+
end
|
58
|
+
|
59
|
+
def provider_local_token_path
|
60
|
+
@_provider_local_token_path ||= tmp_token_path(provider)
|
61
|
+
end
|
62
|
+
|
63
|
+
def retrieve_persisted_token
|
64
|
+
File.read(provider_local_token_path) if File.file?(provider_local_token_path)
|
65
|
+
end
|
66
|
+
|
67
|
+
def parse_response(http_result)
|
68
|
+
case http_result
|
69
|
+
when Net::HTTPOK
|
70
|
+
JSON.parse(http_result.body, { symbolize_names: true })
|
71
|
+
else
|
72
|
+
raise(StandardError, "Request failed with status code #{http_result.code}. #{http_result.body}")
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def post(url, params:, headers: { "Accept" => "application/json" })
|
78
|
+
base_uri = URI(url)
|
79
|
+
enc_params = URI.encode_www_form(params)
|
80
|
+
http_result = Net::HTTP.post(base_uri, enc_params, headers)
|
81
|
+
parse_response(http_result)
|
82
|
+
end
|
83
|
+
|
84
|
+
def poll_for_token(auth_data)
|
85
|
+
interval = auth_data[:interval]
|
86
|
+
loop do
|
87
|
+
res = post(
|
88
|
+
uris["token_req"],
|
89
|
+
params: {
|
90
|
+
client_id: client_id,
|
91
|
+
device_code: auth_data[:device_code],
|
92
|
+
grant_type: grant_type
|
93
|
+
}
|
94
|
+
)
|
95
|
+
|
96
|
+
if res.key?(:error)
|
97
|
+
case res[:error]
|
98
|
+
when "authorization_pending"
|
99
|
+
# dont hit the endpoint too fast such that we get rate limited
|
100
|
+
sleep interval
|
101
|
+
next
|
102
|
+
when "slow_down"
|
103
|
+
# increase polling interval incase rate limited
|
104
|
+
interval = res["interval"]
|
105
|
+
sleep interval
|
106
|
+
next
|
107
|
+
when "access_denied"
|
108
|
+
# user clicks cancel button
|
109
|
+
raise(StandardError, "Access denied while authorizing #{provider} access.")
|
110
|
+
break
|
111
|
+
else
|
112
|
+
raise(StandardError, res)
|
113
|
+
break
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# We won't be running this script regularly. Thus storing in /tmp/
|
118
|
+
# for temporary reuse of token till machine is rebooted
|
119
|
+
File.write(provider_local_token_path, res[:access_token])
|
120
|
+
FileUtils.chmod(0600, provider_local_token_path)
|
121
|
+
|
122
|
+
self.access_token = res[:access_token]
|
123
|
+
ui.info("You've been authenticated!")
|
124
|
+
break
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def access_token_present?
|
129
|
+
!(access_token.nil? || access_token.empty?)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "octokit"
|
4
|
+
|
5
|
+
require_relative "../base"
|
6
|
+
require_relative "../../exception_handler"
|
7
|
+
require_relative "auth"
|
8
|
+
require_relative "../../utils"
|
9
|
+
|
10
|
+
module Neetob
|
11
|
+
class CLI
|
12
|
+
module Github
|
13
|
+
class Base < CLI::Base
|
14
|
+
include Utils
|
15
|
+
attr_accessor :client
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
super()
|
19
|
+
auth_client = Auth.new(**read_and_parse_auth_params_from_env)
|
20
|
+
unless auth_client.token_persisted?
|
21
|
+
auth_client.start_oauth2_device_flow
|
22
|
+
end
|
23
|
+
@client = Octokit::Client.new(access_token: auth_client.access_token)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def read_and_parse_auth_params_from_env
|
29
|
+
hash_with_keys_of_string_type = JSON.parse(ENV["AUTH_PARAMS"])
|
30
|
+
symbolize_keys(hash_with_keys_of_string_type)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
require_relative "labels/commands"
|
5
|
+
require_relative "issues/commands"
|
6
|
+
require_relative "search"
|
7
|
+
require_relative "protect_branch"
|
8
|
+
require_relative "login"
|
9
|
+
require_relative "make_pr/commands"
|
10
|
+
|
11
|
+
module Neetob
|
12
|
+
class CLI
|
13
|
+
module Github
|
14
|
+
class Commands < Thor
|
15
|
+
desc "labels", "Interact with the labels of Github repos"
|
16
|
+
subcommand "labels", Labels::Commands
|
17
|
+
|
18
|
+
desc "issues", "Interact with the issues of Github repos"
|
19
|
+
subcommand "issues", Issues::Commands
|
20
|
+
|
21
|
+
desc "make-pr", "Create PRs across multiple Github repos"
|
22
|
+
subcommand "make_pr", MakePr::Commands
|
23
|
+
|
24
|
+
desc "search", "Find the lines matching the given keyword in the specified file across all the neeto apps"
|
25
|
+
option :apps, type: :array, aliases: "-a", required: true, desc: "Github app names. Can be matched using the '*' wildcard. Example: \"neeto*\" \"neeto-cal-web\""
|
26
|
+
option :keyword, type: :string, aliases: "-k", desc: "Keyword which needs to be searched", required: true
|
27
|
+
option :path, type: :string, aliases: "-p",
|
28
|
+
desc: "Path of the file in which you want to search the given keyword.", required: true
|
29
|
+
def search
|
30
|
+
Search.new(options[:apps], options[:keyword], options[:path], options[:sandbox]).run
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "login", "Update the Github access token by authenticating via browser"
|
34
|
+
def login
|
35
|
+
Login.new
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "protect_branch", "Protect the specified branch with the given rules"
|
39
|
+
option :branch, type: :string, aliases: "-b",
|
40
|
+
desc: "Name of the branch whose protections rules needs to be updated", required: true
|
41
|
+
option :path, type: :string, aliases: "-p",
|
42
|
+
desc: "The JSON file path which specify all the required rules for branch protection"
|
43
|
+
option :apps, type: :array, aliases: "-a", required: true, desc: "Github app names. Can be matched using the '*' wildcard. Example: \"neeto*\" \"neeto-cal-web\""
|
44
|
+
def protect_branch
|
45
|
+
ProtectBranch.new(options[:branch], options[:apps], options[:path], options[:sandbox]).run
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
|
5
|
+
require_relative "list"
|
6
|
+
require_relative "create"
|
7
|
+
require_relative "../../sub_command_base"
|
8
|
+
|
9
|
+
module Neetob
|
10
|
+
class CLI
|
11
|
+
module Github
|
12
|
+
module Issues
|
13
|
+
class Commands < SubCommandBase
|
14
|
+
class_option :apps,
|
15
|
+
{
|
16
|
+
type: :array, aliases: "-a", required: true,
|
17
|
+
desc: "Github app names. Can be matched using the '*' wildcard. Example: \"neeto*\" \"neeto-cal-web\""
|
18
|
+
}
|
19
|
+
|
20
|
+
desc "list", "List the issues in the Github repos"
|
21
|
+
option :state, type: :string, default: "open", aliases: "-s", desc: "State of the issues. Can be open or closed."
|
22
|
+
option :assignee, type: :string, desc: "Username of the current assignee. Can also use \"none\"."
|
23
|
+
option :label, type: :string, aliases: "-l", desc: "Label name to filter out the issues"
|
24
|
+
option :count, type: :boolean, aliases: "-c", desc: "Also shows the count of issues"
|
25
|
+
option :search, type: :string, desc: "Can provide custom query to filter or sort issues. Example: \"created:2022-11-07..2022-11-08 sort:comments-asc\""
|
26
|
+
def list
|
27
|
+
List.new(
|
28
|
+
options[:apps], options[:assignee], options[:state], options[:search], options[:count],
|
29
|
+
options[:label], options[:sandbox]).run
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "create", "Create a issue in the Github repos"
|
33
|
+
option :title, type: :string, required: true, aliases: "-t", desc: "Title of the issue"
|
34
|
+
option :description, type: :string, aliases: "-d", desc: "Description of the issue"
|
35
|
+
option :assignee, type: :string, desc: "Username of the user you want to assign this issue."
|
36
|
+
option :labels, type: :string, desc: "List of comma separated labels you want to add in this issue. Example: \"--labels bug,ui\""
|
37
|
+
def create
|
38
|
+
Create.new(
|
39
|
+
options[:apps],
|
40
|
+
options[:title],
|
41
|
+
options[:description],
|
42
|
+
options[:assignee],
|
43
|
+
options[:labels],
|
44
|
+
options[:sandbox]
|
45
|
+
).run
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
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 Issues
|
11
|
+
class Create < Base
|
12
|
+
attr_accessor :apps, :issue_title, :issue_description, :issue_assignee, :issue_labels, :sandbox
|
13
|
+
|
14
|
+
def initialize(apps, issue_title, issue_description = "", issue_assignee = "", issue_labels = "",
|
15
|
+
sandbox = false)
|
16
|
+
super()
|
17
|
+
@apps = apps
|
18
|
+
@issue_title = issue_title
|
19
|
+
@issue_description = issue_description
|
20
|
+
@issue_assignee = issue_assignee
|
21
|
+
@issue_labels = issue_labels
|
22
|
+
@sandbox = sandbox
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
matching_apps = find_all_matching_apps(apps, :github, sandbox)
|
27
|
+
matching_apps.each do |app|
|
28
|
+
ui.info("\n Creating issue in \"#{app}\" \n")
|
29
|
+
begin
|
30
|
+
issue_options = { assignee: issue_assignee, labels: issue_labels }
|
31
|
+
issue = client.create_issue(app, issue_title, issue_description, issue_options)
|
32
|
+
ui.success("Created the issue successfully \nLink: #{issue[:html_url]}")
|
33
|
+
rescue StandardError => e
|
34
|
+
ExceptionHandler.new(e).process
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
require "action_view"
|
5
|
+
|
6
|
+
require_relative "../base"
|
7
|
+
|
8
|
+
module Neetob
|
9
|
+
class CLI
|
10
|
+
module Github
|
11
|
+
module Issues
|
12
|
+
class List < Base
|
13
|
+
include ActionView::Helpers::DateHelper
|
14
|
+
|
15
|
+
attr_accessor :apps, :issue_state, :issue_assignee, :issue_search_query, :show_issues_count, :issue_label,
|
16
|
+
:sandbox
|
17
|
+
|
18
|
+
def initialize(apps, issue_assignee = "", issue_state = "open",
|
19
|
+
issue_search_query = "", show_issues_count = false, issue_label = "",
|
20
|
+
sandbox = false)
|
21
|
+
super()
|
22
|
+
@apps = apps
|
23
|
+
@issue_state = issue_state
|
24
|
+
@issue_assignee = issue_assignee
|
25
|
+
@show_issues_count = show_issues_count
|
26
|
+
@issue_search_query = issue_search_query
|
27
|
+
@issue_label = issue_label
|
28
|
+
@sandbox = sandbox
|
29
|
+
end
|
30
|
+
|
31
|
+
def run
|
32
|
+
matching_apps = find_all_matching_apps(apps, :github, sandbox)
|
33
|
+
matching_apps.each do |app|
|
34
|
+
ui.info("\n Issues of #{app} \n")
|
35
|
+
begin
|
36
|
+
issues = client.search_issues(uri_with_query_options(app))
|
37
|
+
ui.info("There are #{issues[:total_count]} issues with matching query") if show_issues_count
|
38
|
+
table_rows = create_table(issues[:items])
|
39
|
+
table = Terminal::Table.new headings: table_columns, rows: table_rows
|
40
|
+
ui.success(table)
|
41
|
+
rescue StandardError => e
|
42
|
+
ExceptionHandler.new(e).process
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def table_columns
|
50
|
+
issue_label.nil? ?
|
51
|
+
["Title", "Created at", "Assignee", "Link"] :
|
52
|
+
["Title", "Created at", "Assignee", "Link", "Labels"]
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_table(issues)
|
56
|
+
issues.map do |issue|
|
57
|
+
row_data = [
|
58
|
+
issue[:title],
|
59
|
+
"#{distance_of_time_in_words(issue[:created_at], Time.now)} ago",
|
60
|
+
issue.dig(:assignee, :login),
|
61
|
+
issue[:html_url]
|
62
|
+
]
|
63
|
+
issue_label.nil? ? row_data : row_data.push(labels_names(issue[:labels]))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def uri_with_query_options(app)
|
68
|
+
uri = "repo:#{app} is:issue state:#{issue_state}"
|
69
|
+
unless issue_label.nil?
|
70
|
+
check_valid_labels(app)
|
71
|
+
uri.concat(" label:#{issue_label}")
|
72
|
+
end
|
73
|
+
uri.concat(issue_assignee == "none" ? " no:assignee" : " assignee:#{issue_assignee}") if issue_assignee
|
74
|
+
"#{uri} #{issue_search_query}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def labels_names(labels)
|
78
|
+
labels.map { |label| label[:name] }.join(", ")
|
79
|
+
end
|
80
|
+
|
81
|
+
def check_valid_labels(app)
|
82
|
+
issue_label.split(",").each { |label| valid_label?(app, label) }
|
83
|
+
end
|
84
|
+
|
85
|
+
def valid_label?(app, label)
|
86
|
+
client.label(app, label)
|
87
|
+
rescue Octokit::NotFound => e
|
88
|
+
ui.error("There is no \"#{label}\" label in the \"#{app}\" repo.")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
|
5
|
+
require_relative "list"
|
6
|
+
require_relative "show"
|
7
|
+
require_relative "upsert"
|
8
|
+
require_relative "delete_all"
|
9
|
+
require_relative "delete"
|
10
|
+
require_relative "update"
|
11
|
+
require_relative "../../sub_command_base"
|
12
|
+
|
13
|
+
module Neetob
|
14
|
+
class CLI
|
15
|
+
module Github
|
16
|
+
module Labels
|
17
|
+
class Commands < SubCommandBase
|
18
|
+
class_option :apps,
|
19
|
+
{
|
20
|
+
type: :array, aliases: "-a", required: true,
|
21
|
+
desc: "Github app names. Can be matched using the '*' wildcard. Example: \"neeto*\" \"neeto-cal-web\""
|
22
|
+
}
|
23
|
+
|
24
|
+
desc "list", "List all the labels in the Github repos"
|
25
|
+
def list
|
26
|
+
List.new(options[:apps], options[:sandbox]).run
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "show", "Show details about the given label in the Github repos"
|
30
|
+
option :name, type: :string, aliases: "-n", required: true, desc: "Name of the label"
|
31
|
+
def show
|
32
|
+
Show.new(options[:apps], options[:name], options[:sandbox]).run
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "upsert", "Create and update labels in the Github repos"
|
36
|
+
option :path, type: :string, aliases: "-p", desc: "The JSON file path which has a list of all the required labels. Each label should have name. The color and description are optional"
|
37
|
+
def upsert
|
38
|
+
Upsert.new(options[:apps], options[:path], options[:sandbox]).run
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "delete_all", "Delete all the labels from the Github repos"
|
42
|
+
def delete_all
|
43
|
+
DeleteAll.new(options[:apps], options[:sandbox]).run
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "delete", "Delete some labels from the Github repos"
|
47
|
+
option :labels, type: :array, required: true, desc: "Labels you want to delete from the repos."
|
48
|
+
def delete
|
49
|
+
Delete.new(options[:apps], options[:labels], options[:sandbox]).run
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "update", "Update a label name in Github repos"
|
53
|
+
option :old_name, type: :string, required: true, desc: "Current label name which needs to be updated"
|
54
|
+
option :new_name, type: :string, required: true, desc: "New name for the updated label"
|
55
|
+
def update
|
56
|
+
Update.new(options[:apps], options[:old_name], options[:new_name], options[:sandbox]).run
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,44 @@
|
|
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
|
13
|
+
|
14
|
+
def initialize(apps, labels, sandbox = false)
|
15
|
+
super()
|
16
|
+
@labels = labels
|
17
|
+
@apps = apps
|
18
|
+
@sandbox = sandbox
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
matching_apps = find_all_matching_apps(apps, :github, sandbox)
|
23
|
+
matching_apps.each do |app|
|
24
|
+
ui.info("\n Deleting labels from #{app} repo \n")
|
25
|
+
labels.each do |label|
|
26
|
+
delete_label(app, label)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def delete_label(app, label)
|
34
|
+
if client.delete_label!(app, label)
|
35
|
+
ui.success("The \"#{label}\" label deleted successfully")
|
36
|
+
else
|
37
|
+
ui.error("The \"#{label}\" label can't be deleted. Please check and try again")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,48 @@
|
|
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
|
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
|
+
matching_apps.each do |app|
|
23
|
+
ui.info("\n Working on #{app} repo \n")
|
24
|
+
begin
|
25
|
+
labels = client.labels(app)
|
26
|
+
labels.each do |label|
|
27
|
+
delete_label(app, label)
|
28
|
+
end
|
29
|
+
rescue StandardError => e
|
30
|
+
ExceptionHandler.new(e).process
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def delete_label(app, label_details)
|
38
|
+
if client.delete_label!(app, label_details[:name])
|
39
|
+
ui.success("The \"#{label_details[:name]}\" label deleted successfully")
|
40
|
+
else
|
41
|
+
ui.error("The \"#{label_details[:name]}\" label can't be deleted. Please try again")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,36 @@
|
|
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
|
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
|
+
matching_apps.each do |app|
|
23
|
+
ui.info("\n Labels of #{app} \n")
|
24
|
+
begin
|
25
|
+
labels = client.labels(app)
|
26
|
+
ui.success(labels)
|
27
|
+
rescue StandardError => e
|
28
|
+
ExceptionHandler.new(e).process
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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
|
13
|
+
|
14
|
+
def initialize(apps, label_name, sandbox = false)
|
15
|
+
super()
|
16
|
+
@apps = apps
|
17
|
+
@label_name = label_name
|
18
|
+
@sandbox = sandbox
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
matching_apps = find_all_matching_apps(apps, :github, sandbox)
|
23
|
+
matching_apps.each do |app|
|
24
|
+
ui.info("\n \"#{label_name}\" label details from #{app} \n")
|
25
|
+
begin
|
26
|
+
label_details = client.label(app, label_name)
|
27
|
+
ui.success(label_details.inspect)
|
28
|
+
rescue StandardError => e
|
29
|
+
ExceptionHandler.new(e).process
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,40 @@
|
|
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
|
13
|
+
|
14
|
+
def initialize(apps, old_name, new_name, sandbox = false)
|
15
|
+
super()
|
16
|
+
@apps = apps
|
17
|
+
@sandbox = sandbox
|
18
|
+
@old_name = old_name
|
19
|
+
@new_name = new_name
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
matching_apps = find_all_matching_apps(apps, :github, sandbox)
|
24
|
+
matching_apps.each do |app|
|
25
|
+
ui.info("\n Updating label for #{app} repo \n")
|
26
|
+
update_label!(app, old_name, new_name)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def update_label!(app, old_name, new_name)
|
33
|
+
client.update_label(app, old_name, { name: new_name })
|
34
|
+
ui.success("Label \"#{old_name}\" updated to \"#{new_name}\" successfully")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|