neetob 0.5.69 → 0.5.77

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/.env +2 -1
  3. data/.neetoci/default.yml +1 -1
  4. data/.ruby-version +1 -1
  5. data/Gemfile.lock +44 -21
  6. data/README.md +11 -0
  7. data/bookmarks.md +113 -113
  8. data/data/github-labels.json +80 -45
  9. data/data/repo-team-leads.json +82 -0
  10. data/exe/neetob +1 -1
  11. data/lib/neetob/cli/base.rb +35 -5
  12. data/lib/neetob/cli/cloudflare/automatic_https_rewrites.rb +34 -0
  13. data/lib/neetob/cli/cloudflare/base.rb +2 -2
  14. data/lib/neetob/cli/cloudflare/commands.rb +7 -0
  15. data/lib/neetob/cli/github/active_record_doctor.rb +1 -1
  16. data/lib/neetob/cli/github/brakeman.rb +1 -1
  17. data/lib/neetob/cli/github/bundle_audit.rb +1 -1
  18. data/lib/neetob/cli/github/issues/helpers.rb +17 -4
  19. data/lib/neetob/cli/github/make_pr/base.rb +1 -1
  20. data/lib/neetob/cli/github/repositories/pull_requests.rb +19 -0
  21. data/lib/neetob/cli/github/repositories/team_leads.rb +34 -0
  22. data/lib/neetob/cli/github/unused_assets_audit.rb +5 -1
  23. data/lib/neetob/cli/monthly_audit/github_issue_creation.rb +57 -17
  24. data/lib/neetob/cli/monthly_audit/instances_and_addons/cloudflare/{bot_protection_enabled.rb → automatic_https_rewrites_is_enabled.rb} +11 -9
  25. data/lib/neetob/cli/monthly_audit/instances_and_addons/cloudflare/main.rb +2 -2
  26. data/lib/neetob/cli/monthly_audit/instances_and_addons/cronitor/setup_correctly_for_landing_pages.rb +3 -2
  27. data/lib/neetob/cli/monthly_audit/instances_and_addons/honeybadger/setup_correctly_for_apps.rb +28 -29
  28. data/lib/neetob/cli/monthly_audit/instances_and_addons/main.rb +5 -5
  29. data/lib/neetob/cli/monthly_audit/instances_and_addons/neeto_deploy_or_heroku/cloudfront_cdn_enabled.rb +0 -17
  30. data/lib/neetob/cli/monthly_audit/instances_and_addons/neeto_deploy_or_heroku/essential_environment_variables_set.rb +0 -15
  31. data/lib/neetob/cli/monthly_audit/instances_and_addons/neeto_deploy_or_heroku/main.rb +0 -3
  32. data/lib/neetob/cli/monthly_audit/instances_and_addons/neeto_deploy_or_heroku/scheduled_exports_enabled.rb +2 -4
  33. data/lib/neetob/cli/monthly_audit/instances_and_addons/neeto_deploy_or_heroku/ssl_certificates_over_thirty_days_from_expiry.rb +67 -34
  34. data/lib/neetob/cli/monthly_audit/misc/main.rb +1 -1
  35. data/lib/neetob/cli/monthly_audit/misc/sparkpost_sub_account_used_for_all_apps.rb +24 -18
  36. data/lib/neetob/cli/monthly_audit/security/code/active_record_doctor.rb +2 -2
  37. data/lib/neetob/cli/monthly_audit/security/code/brakeman.rb +7 -4
  38. data/lib/neetob/cli/monthly_audit/security/code/bundle_audit.rb +13 -4
  39. data/lib/neetob/cli/monthly_audit/security/code/fasterer.rb +2 -2
  40. data/lib/neetob/cli/monthly_audit/security/code/yarn_audit.rb +1 -1
  41. data/lib/neetob/cli/monthly_audit/security/github/dependabot_prs_merged.rb +20 -5
  42. data/lib/neetob/cli/monthly_audit/security/github/dependabot_turned_on.rb +25 -21
  43. data/lib/neetob/cli/neeto_deploy/autoscaling_config.rb +1 -1
  44. data/lib/neetob/cli/neeto_deploy/certificates.rb +1 -1
  45. data/lib/neetob/cli/neeto_deploy/commands.rb +7 -0
  46. data/lib/neetob/cli/neeto_deploy/config_vars/list.rb +1 -1
  47. data/lib/neetob/cli/neeto_deploy/config_vars/remove.rb +1 -1
  48. data/lib/neetob/cli/neeto_deploy/config_vars/upsert.rb +1 -1
  49. data/lib/neetob/cli/neeto_deploy/scheduled_exports.rb +1 -1
  50. data/lib/neetob/cli/neeto_deploy/unique_email_domains.rb +165 -0
  51. data/lib/neetob/cli/sre/base.rb +13 -13
  52. data/lib/neetob/cli/sre/check_essential_env.rb +7 -2
  53. data/lib/neetob/cli/sre/checklist.rb +2 -2
  54. data/lib/neetob/version.rb +1 -1
  55. data/neetob.gemspec +1 -1
  56. data/package.json +30 -0
  57. data/playwright.config.ts +39 -0
  58. data/scripts/config/.env.local +17 -0
  59. data/scripts/constants/auditData.ts +402 -0
  60. data/scripts/constants/routes.ts +30 -0
  61. data/scripts/constants/selectors.ts +4 -0
  62. data/scripts/constants/table.ts +30 -0
  63. data/scripts/constants/texts.ts +46 -0
  64. data/scripts/constants/userAgents.ts +14 -0
  65. data/scripts/utils/markdown.ts +23 -0
  66. data/scripts/workflows/dependabot.ts +104 -0
  67. data/scripts/workflows/honeybadger.ts +169 -0
  68. data/scripts/workflows/sparkpost.ts +204 -0
  69. data/tsconfig.json +35 -0
  70. data/yarn.lock +2216 -0
  71. metadata +24 -6
  72. data/lib/neetob/cli/monthly_audit/instances_and_addons/neeto_deploy_or_heroku/auto_scaling_enabled.rb +0 -67
@@ -79,51 +79,6 @@
79
79
  "description": "Something isn't working.",
80
80
  "color": "D73A4A"
81
81
  },
82
- {
83
- "name": "cypress-completed",
84
- "description": "Cypress tests have finished running.",
85
- "color": "FEF2C0"
86
- },
87
- {
88
- "name": "cypress-flaky-test",
89
- "description": "Fix cypress flaky tests.",
90
- "color": "FEF2C0"
91
- },
92
- {
93
- "name": "cypress-happy-path-completed",
94
- "description": "Cypress happy path tests have finished running.",
95
- "color": "FEF2C0"
96
- },
97
- {
98
- "name": "cypress-happy-path-run",
99
- "description": "Run the Cypress tests with the tag happy-path.",
100
- "color": "FEF2C0"
101
- },
102
- {
103
- "name": "cypress-happy-path-triggered",
104
- "description": "Cypress happy path tests have been triggered.",
105
- "color": "FEF2C0"
106
- },
107
- {
108
- "name": "cypress-needed",
109
- "description": "Cypress tests need to be written.",
110
- "color": "FEF2C0"
111
- },
112
- {
113
- "name": "cypress-run",
114
- "description": "Run the Cypress tests.",
115
- "color": "FEF2C0"
116
- },
117
- {
118
- "name": "cypress-triggered",
119
- "description": "Cypress tests have been triggered.",
120
- "color": "FEF2C0"
121
- },
122
- {
123
- "name": "caught-by-cypress",
124
- "description": "Cypress tests have caught the bug.",
125
- "color": "FEF2C0"
126
- },
127
82
  {
128
83
  "name": "playwright-completed",
129
84
  "description": "Playwright tests have finished running.",
@@ -164,11 +119,61 @@
164
119
  "description": "Playwright tests have been triggered.",
165
120
  "color": "c2d6d6"
166
121
  },
122
+ {
123
+ "name": "playwright-staging-run",
124
+ "description": "Run Playwright tests on staging.",
125
+ "color": "3ab13b"
126
+ },
127
+ {
128
+ "name": "playwright-staging-triggered",
129
+ "description": "Playwright tests have been triggered on staging.",
130
+ "color": "3ab13b"
131
+ },
132
+ {
133
+ "name": "playwright-staging-completed",
134
+ "description": "Playwright tests have finished running on staging.",
135
+ "color": "3ab13b"
136
+ },
137
+ {
138
+ "name": "playwright-staging-diff-run",
139
+ "description": "Run selected Playwright tests on staging based on PR changes.",
140
+ "color": "DDF4FF"
141
+ },
142
+ {
143
+ "name": "playwright-staging-diff-triggered",
144
+ "description": "Playwright tests for PR changes have been triggered on staging.",
145
+ "color": "DDF4FF"
146
+ },
147
+ {
148
+ "name": "playwright-staging-diff-completed",
149
+ "description": "Playwright tests for PR changes have finished on staging.",
150
+ "color": "DDF4FF"
151
+ },
152
+ {
153
+ "name": "playwright-fix",
154
+ "description": "Fix broken or unstable Playwright tests.",
155
+ "color": "c2d6d6"
156
+ },
167
157
  {
168
158
  "name": "caught-by-playwright",
169
159
  "description": "Playwright tests have caught the bug.",
170
160
  "color": "c2d6d6"
171
161
  },
162
+ {
163
+ "name": "qa-needed",
164
+ "description": "Issue is ready for QA testing.",
165
+ "color": "c2d6d6"
166
+ },
167
+ {
168
+ "name": "qa-passed",
169
+ "description": "Issue has passed QA testing.",
170
+ "color": "c2d6d6"
171
+ },
172
+ {
173
+ "name": "qa-failed",
174
+ "description": "Issue did not pass QA testing.",
175
+ "color": "c2d6d6"
176
+ },
172
177
  {
173
178
  "name": "documentation",
174
179
  "description": "Improvements or additions to documentation.",
@@ -338,5 +343,35 @@
338
343
  "name": "caught-by-replay",
339
344
  "description": "This issue was identified within neetoReplay recordings.",
340
345
  "color": "63C2DB"
346
+ },
347
+ {
348
+ "name": "customer",
349
+ "description": "A customer has raised this issue and is probably waiting to get it fixed.",
350
+ "color": "EB5B00"
351
+ },
352
+ {
353
+ "name": "inform-when-done",
354
+ "description": "Notify the requester or customer once this issue is completed.",
355
+ "color": "E9ED10"
356
+ },
357
+ {
358
+ "name": "nextup",
359
+ "description": "Next Up",
360
+ "color": "FF7777"
361
+ },
362
+ {
363
+ "name": "payment",
364
+ "description": "This issue is related to payment processing, subscriptions, or payment workflows.",
365
+ "color": "D93F0B"
366
+ }
367
+ {
368
+ "name": "billing",
369
+ "description": "Unable to bill the client.",
370
+ "color": "006B75"
371
+ },
372
+ {
373
+ "name": "feature",
374
+ "description": "Requests or tasks related to new functionality or enhancements to existing features.",
375
+ "color": "0E8A16"
341
376
  }
342
377
  ]
@@ -0,0 +1,82 @@
1
+ {
2
+ "neeto-auth-web": "Thejus-Paul",
3
+ "neeto-form-web": "chiraggshah",
4
+ "neeto-cal-web": "sayoojtmc",
5
+ "neeto-chat-web": "akashdotsrivastava",
6
+ "neeto-desk-web": "akashdotsrivastava",
7
+ "neeto-kb-web": "josephmathew900",
8
+ "neeto-quiz-web": "akashdotsrivastava",
9
+ "neeto-site-web": "soorajbhaskaran",
10
+ "neeto-runner-web": "sandip-mane",
11
+ "neeto-replay-web": "josephmathew900",
12
+ "neeto-invoice-web": "anil-anand",
13
+ "neeto-planner-web": "sandip-mane",
14
+ "neeto-course-web": "akashdotsrivastava",
15
+ "neeto-wireframe-web": "labeebklatif",
16
+ "neeto-engage-web": "josephmathew900",
17
+ "neeto-crm-web": "chiraggshah",
18
+ "neeto-deploy-web": "unnitallman",
19
+ "neeto-ci-web": "unnitallman",
20
+ "neeto-git-web": "unnitallman",
21
+ "neeto-record-web": "chiraggshah",
22
+ "neeto-tower-web": "chiraggshah",
23
+ "neeto-publish-web": "josephmathew900",
24
+ "neeto-playdash-web": "VarunSriram99",
25
+ "neeto-code-web": "akashdotsrivastava",
26
+ "neeto-pay-web": "yedhink",
27
+ "neeto-bugwatch-web": "yedhink",
28
+ "neeto-wheel-nano": "NO TL FOUND",
29
+ "neeto-message-templates-nano": "chiraggshah",
30
+ "neeto-projects-nano": "",
31
+ "neeto-fields-nano": "chiraggshah",
32
+ "neeto-webhooks-nano": "NO TL FOUND",
33
+ "neeto-image-uploader-nano": "NO TL FOUND",
34
+ "neeto-thank-you-nano": "chiraggshah",
35
+ "neeto-email-notifications-nano": "chiraggshah",
36
+ "neeto-api-keys-nano": "NO TL FOUND",
37
+ "neeto-templates-nano": "NO TL FOUND",
38
+ "neeto-activities-nano": "sandip-mane",
39
+ "neeto-tags-nano": "NO TL FOUND",
40
+ "neeto-team-members-nano": "unnitallman",
41
+ "neeto-filters-nano": "NO TL FOUND",
42
+ "neeto-rules-nano": "akashdotsrivastava",
43
+ "neeto-form-nano": "chiraggshah",
44
+ "neeto-slack-nano": "chiraggshah",
45
+ "neeto-payments-nano": "sandip-mane",
46
+ "neeto-approvals-nano": "akashdotsrivastava",
47
+ "neeto-integrations-nano": "chiraggshah",
48
+ "neeto-github-nano": "unnitallman",
49
+ "neeto-comments-nano": "NO TL FOUND",
50
+ "neeto-rate-limit-nano": "sandip-mane",
51
+ "neeto-access-control-nano": "sandip-mane",
52
+ "neeto-themes-nano": "NO TL FOUND",
53
+ "neeto-redirect-urls-nano": "",
54
+ "neeto-folders-nano": "labeebklatif",
55
+ "app-version-control": "vishnu-m",
56
+ "neeto-crm-nano": "soorajbhaskaran",
57
+ "neeto-device-information-nano": "lavesh-saluja32",
58
+ "neeto-email-delivery-nano": "chiraggshah",
59
+ "neeto-ip-restrictions-nano": "unnitallman",
60
+ "neeto-invite-links-nano": "sandip-mane",
61
+ "neeto-custom-domains-nano": "unnitallman",
62
+ "neeto-notifications-nano": "chiraggshah",
63
+ "neeto-emails": "philson-philip",
64
+ "neeto-compliance": "unnitallman",
65
+ "neeto-sso": "NO TL FOUND",
66
+ "neeto-commons-backend": "unnitallman",
67
+ "neeto-mail-interceptor": "sandip-mane",
68
+ "neeto-org-incineration-nano": "unnitallman",
69
+ "neeto-editor-nano": "NO TL FOUND",
70
+ "neeto-seo-nano": "NO TL FOUND",
71
+ "neeto-commons-frontend": "josephmathew900",
72
+ "eslint-plugin-neeto": "josephmathew900",
73
+ "neeto-ui": "josephmathew900",
74
+ "neeto-icons": "praveen-murali-ind",
75
+ "neeto-editor": "NO TL FOUND",
76
+ "neeto-molecules": "josephmathew900",
77
+ "babel-preset-neeto": "josephmathew900",
78
+ "neeto-commons-repl": "labeebklatif",
79
+ "neeto-cist": "NO TL FOUND",
80
+ "neeto-playwright-commons": "NO TL FOUND",
81
+ "neeto-playwright-reporter": "NO TL FOUND"
82
+ }
data/exe/neetob CHANGED
@@ -5,7 +5,7 @@ require "dotenv"
5
5
 
6
6
  MIN_RUBY_VERSION = File.read(File.expand_path("../.ruby-version", __dir__)).strip
7
7
 
8
- if RUBY_VERSION < MIN_RUBY_VERSION
8
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new(MIN_RUBY_VERSION)
9
9
  raise RuntimeError, "neetob requires Ruby version of #{MIN_RUBY_VERSION} or higher"
10
10
  end
11
11
 
@@ -34,6 +34,14 @@ module Neetob
34
34
  return "bigbinary-website"
35
35
  end
36
36
 
37
+ if domain == "neetocoursesite"
38
+ return "neeto-course-site"
39
+ end
40
+
41
+ if domain == "neetowebpage"
42
+ return "neeto-site-eui"
43
+ end
44
+
37
45
  if domain.start_with?("neeto")
38
46
  app = domain.sub("neeto", "neeto-")
39
47
  else
@@ -85,19 +93,19 @@ module Neetob
85
93
  def all_engine_repos(sandbox_mode)
86
94
  sandbox_mode ?
87
95
  testing_apps(:github) :
88
- NeetoCompliance::NeetoRepos.nanos_backend.map { |repo| "bigbinary/#{repo}" }
96
+ NeetoCompliance::NeetoRepos.nanos_backend.map { |repo| "neetozone/#{repo}" }
89
97
  end
90
98
 
91
99
  def all_product_repos(sandbox_mode)
92
100
  sandbox_mode ?
93
101
  testing_apps(:github) :
94
- NeetoCompliance::NeetoRepos::products.keys.map { |repo| "bigbinary/#{repo}" }
102
+ NeetoCompliance::NeetoRepos::products.keys.map { |repo| "neetozone/#{repo}" }
95
103
  end
96
104
 
97
105
  def all_nano_repos(sandbox_mode)
98
106
  sandbox_mode ?
99
107
  testing_apps(:github) :
100
- NeetoCompliance::NeetoRepos.nanos_mono_repos.map { |repo| "bigbinary/#{repo}" }
108
+ NeetoCompliance::NeetoRepos.nanos_mono_repos.map { |repo| "neetozone/#{repo}" }
101
109
  end
102
110
 
103
111
  def match_apps(required_apps, available_apps)
@@ -114,7 +122,7 @@ module Neetob
114
122
 
115
123
  def build_app_list_from_neeto_compliance(platform_name, all_neeto_repos)
116
124
  neeto_products = NeetoCompliance::NeetoRepos.products
117
- apps = all_neeto_repos ? fetch_all_neeto_repos : neeto_products.keys
125
+ apps = all_neeto_repos ? fetch_all_neeto_repos : products_and_nanos_repos(:all)
118
126
  [:heroku, :neetodeploy].include?(platform_name) ? add_env_suffix(apps, neeto_products) : prefix_org_name(apps)
119
127
  end
120
128
 
@@ -130,7 +138,7 @@ module Neetob
130
138
  end
131
139
 
132
140
  def prefix_org_name(apps)
133
- apps.map { |app| "bigbinary/#{app}" }
141
+ apps.map { |app| "neetozone/#{app}" }
134
142
  end
135
143
 
136
144
  def testing_apps(platform_name)
@@ -160,6 +168,20 @@ module Neetob
160
168
  NeetoCompliance::NeetoRepos::nanos_mono_repos
161
169
  end
162
170
 
171
+ def products_and_nanos_repos(stack)
172
+ base_repos = NeetoCompliance::NeetoRepos.products.keys + NeetoCompliance::NeetoRepos.nanos_mono_repos
173
+ repos = base_repos
174
+ case stack
175
+ when :backend
176
+ repos = base_repos | NeetoCompliance::NeetoRepos.nanos_backend
177
+ when :frontend
178
+ repos = base_repos | NeetoCompliance::NeetoRepos.nanos_frontend
179
+ else
180
+ repos = base_repos | NeetoCompliance::NeetoRepos.nanos
181
+ end
182
+ repos.reject { |repo| repo.include?("area51") || repo.include?("neeto-datepicker") }
183
+ end
184
+
163
185
  def find_all_matching_gems(gems = ["*"])
164
186
  all_available_gems = NeetoCompliance::NeetoRepos.nanos_mono_repos + NeetoCompliance::NeetoRepos.nanos_backend
165
187
  match_apps(gems || ["*"], all_available_gems)
@@ -177,5 +199,13 @@ module Neetob
177
199
  def print_failure(str)
178
200
  "\u001b[31m#{str}\u001b[0m"
179
201
  end
202
+
203
+ def extract_json_array_from_output(output)
204
+ json_text = output[/\[\s*\[.*?\]\s*\]/m]
205
+
206
+ raise output unless json_text
207
+
208
+ JSON.parse(json_text)
209
+ end
180
210
  end
181
211
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Neetob
6
+ class CLI
7
+ module Cloudflare
8
+ class AutomaticHttpsRewrites < Base
9
+ attr_accessor :domain
10
+
11
+ def initialize(domain)
12
+ super()
13
+ @domain = domain
14
+ end
15
+
16
+ def run
17
+ zone_id = ZONE_IDS[domain.to_sym]
18
+ unless Thread.current[:audit_mode]
19
+ raise(StandardError, "Domain '#{domain}' not found.") if zone_id.nil?
20
+ end
21
+
22
+ url = create_url(zone_id, "settings/automatic_https_rewrites")
23
+ response = get(url)
24
+ value = response.dig(:result, :value)
25
+ automatic_https_rewrites = value == "on" ? print_success(value) : print_failure(value)
26
+ ui.info("Automatic HTTPS rewrites is turned #{automatic_https_rewrites}", print_to_audit_log: false)
27
+ if Thread.current[:audit_mode]
28
+ value
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -55,14 +55,14 @@ module Neetob
55
55
  "neetorunner.net": "8b5b81e94e1238cb7d8bd4062c788233",
56
56
  "neetosite.com": "10a07b451a511a57513a74d40ae3680d",
57
57
  "neetosite.net": "23064d6c435af82b92a102b465d5faf6",
58
- "neetotestify.com": "b2d592bc096b4c1b80c6941bd1a8597c",
59
- "neetotestify.net": "1bbb5bf2ea04121c57a3690d2f40c5dc",
60
58
  "neetotower.com": "9175d2e1bb19735b9b22c101ac162d31",
61
59
  "neetotower.net": "10f9eba21876cd174952b830aba0ba71",
62
60
  "neetowireframe.com": "d6d17a3dab91dc0ca4b9f4f65b086ccc",
63
61
  "neetowireframe.net": "5866b3f9d20b45800d5657ec59ac630e",
64
62
  "neetowebpage.com": "067c86bc40ea1788becbe2f9bf5cb5ca",
65
63
  "neetowebpage.net": "65cdacca073ae5e822682c6938defcbe",
64
+ "neetopay.com": "714fccf30fd8f5eba7c55550a08b13e3",
65
+ "neetopay.net": "785fc7ed6248a122946c1f1310fcade7",
66
66
  "neeto.com": "83eeffbce76df68b60e50d1fa254b3fa",
67
67
  "bigbinary.com": "dc60ee7ecbff0ef5e58e1bb27ad40e89"
68
68
  }
@@ -8,6 +8,7 @@ require_relative "dns_proxy_status"
8
8
  require_relative "ensure_cdn"
9
9
  require_relative "bot_fight_mode"
10
10
  require_relative "verify_spf"
11
+ require_relative "automatic_https_rewrites"
11
12
 
12
13
  module Neetob
13
14
  class CLI
@@ -31,6 +32,12 @@ module Neetob
31
32
  AlwaysUseHttps.new(options[:domain]).process
32
33
  end
33
34
 
35
+ desc "automatic_https_rewrites", "Check if automatic HTTPS rewrites setting is turned on for your domain in Cloudflare"
36
+ option :domain, type: :string, aliases: "-d", required: true, description: "Domain name"
37
+ def automatic_https_rewrites
38
+ AutomaticHttpsRewrites.new(options[:domain]).process
39
+ end
40
+
34
41
  desc "dns_proxy_status", "Check if DNS proxy status is enabled for all DNS records of your domain in Cloudflare"
35
42
  option :domain, type: :string, aliases: "-d", required: true, description: "Domain name"
36
43
  def dns_proxy_status
@@ -51,7 +51,7 @@ module Neetob
51
51
  def setup_db!(repo)
52
52
  `#{cd_to_repo(repo)} && cp config/database.yml.postgresql config/database.yml`
53
53
  `#{cd_to_repo(repo)} && sed -i '' 's/_development/_development_audit/g' config/database.yml`
54
- `#{cd_to_repo(repo)} && bundle exec rake setup`
54
+ `#{cd_to_repo(repo)} && bundle exec rails db:drop db:create db:migrate`
55
55
  end
56
56
  end
57
57
  end
@@ -43,7 +43,7 @@ module Neetob
43
43
  private
44
44
 
45
45
  def run_brakeman(repo)
46
- `#{cd_to_repo(repo)} && brakeman`
46
+ `#{cd_to_repo(repo)} && brakeman --force`
47
47
  end
48
48
 
49
49
  def parse_description(warnings)
@@ -39,7 +39,7 @@ module Neetob
39
39
  private
40
40
 
41
41
  def run_bundle_audit(repo)
42
- `#{cd_to_repo(repo)} && rbenv local 3.3.5 && bundle-audit check`
42
+ `#{cd_to_repo(repo)} && rbenv local 3.3.10 && bundle-audit check`
43
43
  end
44
44
  end
45
45
  end
@@ -11,15 +11,28 @@ module Neetob
11
11
  super()
12
12
  end
13
13
 
14
- def get_issue_with_title(repo, title)
14
+ def get_issue_with_title(repo, regex)
15
15
  begin
16
- issues = client.issues(repo, state: "open")
17
- issue = issues.find { |issue| issue.title == title }
18
- issue
16
+ issues = []
17
+ page = 1
18
+
19
+ loop do
20
+ batch = client.list_issues(repo, state: "open", per_page: 100, page:)
21
+ break if batch.empty?
22
+
23
+ issues.concat(batch)
24
+ page += 1
25
+ end
26
+
27
+ issues.find { |issue| issue.title.match?(regex) }
19
28
  rescue StandardError => e
20
29
  ExceptionHandler.new(e).process
21
30
  end
22
31
  end
32
+
33
+ def close_issue(repo, issue_number)
34
+ client.close_issue(repo, issue_number)
35
+ end
23
36
  end
24
37
  end
25
38
  end
@@ -26,7 +26,7 @@ module Neetob
26
26
  def bundle_install!(repo, local_repo = false)
27
27
  commands = [
28
28
  cd_to_repo(repo, local_repo),
29
- "rbenv local 3.3.5",
29
+ "rbenv local 3.3.10",
30
30
  repo_specific_commands_before_bundle_install(repo),
31
31
  "BUNDLE_GEMFILE='#{repo_path(repo)}/Gemfile' bundle install"
32
32
  ]
@@ -27,6 +27,25 @@ module Neetob
27
27
  end
28
28
  data
29
29
  end
30
+
31
+ def add_comment_to_pr(repo, pr_number, comment_body, assignees = [])
32
+ begin
33
+ client.add_comment(repo, pr_number, comment_body)
34
+ add_assignee(repo, pr_number, assignees) if assignees.any?
35
+ "https://github.com/#{repo}/pull/#{pr_number}"
36
+ rescue StandardError => e
37
+ ExceptionHandler.new(e).process
38
+ nil
39
+ end
40
+ end
41
+
42
+ def add_assignee(repo, pr_number, assignees)
43
+ begin
44
+ client.add_assignees(repo, pr_number, assignees)
45
+ rescue StandardError => e
46
+ ExceptionHandler.new(e).process
47
+ end
48
+ end
30
49
  end
31
50
  end
32
51
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Neetob
6
+ class CLI
7
+ module Github
8
+ module Repositories
9
+ class TeamLeads
10
+ def self.team_lead_for(repo_name)
11
+ team_leads[repo_name]&.strip
12
+ end
13
+
14
+ def self.team_leads
15
+ @_team_leads ||= load_team_leads
16
+ end
17
+
18
+ def self.load_team_leads
19
+ begin
20
+ file_path = File.join(__dir__, "../../../../../data/repo-team-leads.json")
21
+ file = File.read(file_path)
22
+ JSON.parse(file)
23
+ rescue StandardError => e
24
+ ExceptionHandler.new(e).process
25
+ {}
26
+ end
27
+ end
28
+
29
+ private_class_method :team_leads, :load_team_leads
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -68,7 +68,11 @@ module Neetob
68
68
  end
69
69
 
70
70
  def image_file_imported(file, image_path, is_views_path)
71
- regex = is_views_path ? /"#{image_path}"/ : /import .* from "#{image_path}";/
71
+ if is_views_path
72
+ regex = /"#{Regexp.escape(image_path)}"/
73
+ else
74
+ regex = /import .* from ".*#{Regexp.escape(image_path)}.*";/
75
+ end
72
76
  file.match(regex)
73
77
  end
74
78
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  require_relative "../github/base"
4
4
  require_relative "../github/issues/helpers"
5
+ require_relative "../github/repositories/team_leads"
6
+
5
7
  class GithubIssueCreation < Neetob::CLI::Github::Base
6
8
  def initialize
7
9
  super()
@@ -10,26 +12,64 @@ class GithubIssueCreation < Neetob::CLI::Github::Base
10
12
 
11
13
  def create_issue(repo:, title:, description:, labels: "")
12
14
  return if Thread.current[:skip_issue]
15
+ return if repo.include?("bigbinary-website")
16
+
17
+ full_title = build_full_title(title)
18
+ repo_path = "neetozone/#{repo}"
19
+
20
+ # Check for existing issue with exact title match
21
+ existing_issue = find_existing_issue_by_title(repo_path, full_title)
22
+ return existing_issue.html_url if existing_issue
23
+
24
+ # Close any existing issues of the same type
25
+ close_existing_issues_of_same_type(repo_path, title)
13
26
 
14
- month = Thread.current[:month].capitalize.gsub("-", " ")
15
- title = "#{month} Audit - #{title}"
27
+ create_new_issue(repo_path, full_title, description, labels)
28
+ end
29
+
30
+ private
16
31
 
17
- # Checking if the issue already exists
18
- issue = @helpers.get_issue_with_title("bigbinary/#{repo}", title)
19
- if issue
20
- return issue.html_url
32
+ def build_full_title(title)
33
+ month = Thread.current[:month].capitalize.gsub("-", " ")
34
+ "#{month} Audit - #{title}"
21
35
  end
22
36
 
23
- begin
24
- issue = client.create_issue(
25
- "bigbinary/#{repo}",
26
- title,
27
- "## #{title} \n #{description}",
28
- { labels: }
29
- )
30
- issue.html_url
31
- rescue StandardError => e
32
- ExceptionHandler.new(e).process
37
+ def find_existing_issue_by_title(repo_path, full_title)
38
+ title_regex = Regexp.new("^#{Regexp.escape(full_title)}$", Regexp::IGNORECASE)
39
+ @helpers.get_issue_with_title(repo_path, title_regex)
40
+ end
41
+
42
+ def close_existing_issues_of_same_type(repo_path, title)
43
+ type_regex = Regexp.new(Regexp.escape(title), Regexp::IGNORECASE)
44
+ existing_issue = @helpers.get_issue_with_title(repo_path, type_regex)
45
+
46
+ if existing_issue
47
+ @helpers.close_issue(repo_path, existing_issue.number)
48
+ end
49
+ end
50
+
51
+ def create_new_issue(repo_path, full_title, description, labels)
52
+ issue_body = build_issue_body(full_title, description)
53
+ repo_name = repo_path.split("/").last
54
+ assignee = Neetob::CLI::Github::Repositories::TeamLeads.team_lead_for(repo_name)
55
+
56
+ issue_options = { labels: }
57
+ issue_options[:assignee] = assignee if assignee && assignee != "NO TL FOUND"
58
+
59
+ begin
60
+ issue = client.create_issue(
61
+ repo_path,
62
+ full_title,
63
+ issue_body,
64
+ issue_options
65
+ )
66
+ issue.html_url
67
+ rescue StandardError => e
68
+ ExceptionHandler.new(e).process
69
+ end
70
+ end
71
+
72
+ def build_issue_body(full_title, description)
73
+ "## #{full_title}\n\n#{description}"
33
74
  end
34
- end
35
75
  end