hephaestus 0.1.3 → 0.2.2

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +27 -1
  4. data/bin/hephaestus +9 -3
  5. data/lib/hephaestus/app_builder.rb +26 -5
  6. data/lib/hephaestus/exit_on_failure.rb +4 -4
  7. data/lib/hephaestus/generators/app_generator.rb +148 -56
  8. data/lib/hephaestus/generators/config_generator.rb +30 -2
  9. data/lib/hephaestus/generators/core_generator.rb +30 -1
  10. data/lib/hephaestus/generators/deployment_generator.rb +9 -3
  11. data/lib/hephaestus/generators/lib_generator.rb +1 -0
  12. data/lib/hephaestus/generators/sorbet_generator.rb +1 -1
  13. data/lib/hephaestus/version.rb +1 -1
  14. data/lib/hephaestus.rb +8 -0
  15. data/templates/.dockerignore +39 -0
  16. data/templates/.env.sample +6 -0
  17. data/templates/.github/dependabot.yml +12 -7
  18. data/templates/.github/workflows/automerge.yml +5 -85
  19. data/templates/.github/workflows/deploy.yml +30 -0
  20. data/templates/.github/workflows/licenses.yml +11 -31
  21. data/templates/.github/workflows/lint.yml +14 -34
  22. data/templates/.github/workflows/security.yml +9 -32
  23. data/templates/.github/workflows/sorbet.yml +7 -37
  24. data/templates/.github/workflows/test.yml +7 -41
  25. data/templates/.licensed.yml +7 -3
  26. data/templates/.ruby-version +1 -0
  27. data/templates/Dockerfile +79 -0
  28. data/templates/Gemfile.erb +23 -26
  29. data/templates/Procfile.debug +1 -1
  30. data/templates/app/controllers/app_controller.rb +71 -0
  31. data/templates/app/controllers/application_controller.rb +14 -1
  32. data/templates/app/controllers/concerns/authable.rb +20 -2
  33. data/templates/app/controllers/settings_controller.rb +32 -2
  34. data/templates/app/jobs/update_yetto_job.rb +6 -7
  35. data/templates/app/lib/body_parameter/yetto_parameters.rb +32 -0
  36. data/templates/app/lib/path_parameter/settings_parameters.rb +22 -0
  37. data/templates/app/lib/plug_app/middleware/openapi_validation.rb +5 -5
  38. data/templates/app/lib/plug_app/middleware/tracing_attributes.rb +1 -1
  39. data/templates/app/services/http_service.rb +27 -0
  40. data/templates/app/services/yetto_service.rb +24 -32
  41. data/templates/app/views/settings/new.json.jbuilder +21 -0
  42. data/templates/bin/docker-entrypoint +14 -0
  43. data/templates/compose.yml +7 -0
  44. data/templates/config/initializers/environment.rb +5 -8
  45. data/templates/config/initializers/filter_parameter_logging.rb +3 -0
  46. data/templates/config/initializers/opentelemetry.rb +32 -0
  47. data/templates/config/locales/en.yml +32 -0
  48. data/templates/config/locales/settings/en.yml +5 -0
  49. data/templates/lib/plug_app/schemas/api/2023-03-06/components/schemas/yetto.json +2 -2
  50. data/templates/lib/plug_app/schemas/api/2023-03-06/openapi.json +4 -4
  51. data/templates/lib/plug_app/schemas/api/2023-03-06/paths/plug.json +1 -1
  52. data/templates/lib/plug_app/schemas/api/2023-03-06/paths/yetto/after_create_message.json +2 -2
  53. data/templates/lib/plug_app/schemas/api/2023-03-06/paths/yetto/after_create_plug_installation.json +2 -2
  54. data/templates/lib/tasks/test_tasks.rake +6 -2
  55. data/templates/script/edit-credentials +29 -0
  56. data/templates/script/hmac_text +1 -1
  57. data/templates/script/licenses +4 -48
  58. data/templates/script/server +62 -2
  59. data/templates/script/sorbet +7 -0
  60. data/templates/test/controllers/application_controller_test.rb +32 -0
  61. data/templates/test/controllers/settings_controller_test.rb +1 -1
  62. data/templates/test/controllers/yetto_controller_test.rb +1 -1
  63. data/templates/test/fixtures/files/fake_pem_file/fake.pem +27 -0
  64. data/templates/test/jobs/update_yetto_job_test.rb +3 -18
  65. data/templates/test/support/api.rb +1 -1
  66. data/templates/test/support/rails.rb +1 -1
  67. data/templates/test/support/webmocks/slack_webmock.rb +2 -2
  68. data/templates/test/support/webmocks/yetto_webmock.rb +119 -0
  69. data/templates/test/test_helper.rb +16 -3
  70. data/templates/vendor/fly/fly-production.toml +38 -0
  71. data/templates/vendor/fly/fly-staging.toml +33 -0
  72. metadata +39 -16
  73. data/templates/.env.test +0 -4
  74. data/templates/.github/actions/license/action.yml +0 -11
  75. data/templates/.github/actions/setup/action.yml +0 -10
  76. data/templates/.github/actions/sisyphus/action.yml +0 -11
  77. data/templates/.github/actions/sorbet/action.yml +0 -19
  78. data/templates/app/views/settings/index.json.jbuilder +0 -15
  79. data/templates/config/initializers/open_telemetry.rb +0 -27
  80. data/templates/script/security_checks/brakeman +0 -5
  81. data/templates/script/security_checks/bundle-audit +0 -5
  82. data/templates/script/server-debug +0 -5
  83. data/templates/script/typecheck +0 -44
  84. data/templates/test/fixtures/files/.keep +0 -0
  85. data/templates/test/support/webmocks/yetto.rb +0 -94
@@ -0,0 +1,5 @@
1
+ en:
2
+ some_example_heading: "From name"
3
+ some_example_label: "Some example"
4
+ another_example_heading: "Reply-to email address"
5
+ another_example_label: "Another example"
@@ -1,5 +1,5 @@
1
1
  {
2
- "Create${APP}Message": {
2
+ "CreateAppMessage": {
3
3
  "type": "object",
4
4
  "required": [
5
5
  "plug_installation",
@@ -98,7 +98,7 @@
98
98
  },
99
99
  "additionalProperties": false
100
100
  },
101
- "Create${APP}": {
101
+ "CreateApp": {
102
102
  "type": "object",
103
103
  "required": [
104
104
  "plug_installation",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "openapi": "3.0.0",
3
3
  "info": {
4
- "title": "${APP} Plug API",
5
- "description": "An OpenAPI definition for the ${APP} Plug REST API.",
4
+ "title": "App Plug API",
5
+ "description": "An OpenAPI definition for the App Plug REST API.",
6
6
  "version": "2023-03-06",
7
7
  "termsOfService": "https://yetto.app/terms/",
8
8
  "license": {
@@ -23,8 +23,8 @@
23
23
  "/api/2023-03-06/after_create/message": {
24
24
  "$ref": "paths/yetto/after_create_message.json"
25
25
  },
26
- "/${app}/2023-03-06/{plugInstallationId}": {
27
- "$ref": "paths/${app}.json"
26
+ "/app/2023-03-06/{plugInstallationId}": {
27
+ "$ref": "paths/app.json"
28
28
  }
29
29
  }
30
30
  }
@@ -2,7 +2,7 @@
2
2
  "post": {
3
3
  "tags": [
4
4
  "Inbound",
5
- "${APP}"
5
+ "App"
6
6
  ],
7
7
  "description": "This represents something",
8
8
  "operationId": "Post a Yetto message",
@@ -4,13 +4,13 @@
4
4
  "Yetto"
5
5
  ],
6
6
  "description": "After a message is created in Yetto, this delivers it.",
7
- "operationId": "Create a new ${APP}",
7
+ "operationId": "Create a new App",
8
8
  "requestBody": {
9
9
  "required": true,
10
10
  "content": {
11
11
  "application/json": {
12
12
  "schema": {
13
- "$ref": "../../components/schemas/yetto.json#/Create${APP}Message"
13
+ "$ref": "../../components/schemas/yetto.json#/CreateAppMessage"
14
14
  }
15
15
  }
16
16
  }
@@ -4,13 +4,13 @@
4
4
  "Yetto"
5
5
  ],
6
6
  "description": "After a plug installation is created, this executes",
7
- "operationId": "Post a thing",
7
+ "operationId": "Post a plug installation",
8
8
  "requestBody": {
9
9
  "required": true,
10
10
  "content": {
11
11
  "application/json": {
12
12
  "schema": {
13
- "$ref": "../../components/schemas/yetto.json#/Create${APP}"
13
+ "$ref": "../../components/schemas/yetto.json#/CreateAppSwitch"
14
14
  }
15
15
  }
16
16
  }
@@ -4,7 +4,11 @@
4
4
  require "rake/testtask"
5
5
 
6
6
  if Rails.env.development? || Rails.env.test?
7
- require "rubocop/rake_task"
7
+ begin
8
+ require "rubocop/rake_task"
8
9
 
9
- RuboCop::RakeTask.new(:rubocop)
10
+ RuboCop::RakeTask.new(:rubocop)
11
+ rescue LoadError => e
12
+ warn("WARNING: rubocop is not available in this environment: #{e}")
13
+ end
10
14
  end
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ # Initialize flags
6
+ staging=false
7
+ production=false
8
+
9
+ # Check for and parse flags
10
+ for arg in "$@"
11
+ do
12
+ case $arg in
13
+ --staging)
14
+ staging=true
15
+ ;;
16
+ --production)
17
+ production=true
18
+ ;;
19
+ *)
20
+ # Unknown arguments can be ignored or handled here
21
+ ;;
22
+ esac
23
+ done
24
+
25
+ if [[ $staging == true ]]; then
26
+ RAILS_MASTER_KEY=$(op read op://Plug-App/staging-rails-master-key/...) bin/rails credentials:edit -e staging
27
+ else
28
+ RAILS_MASTER_KEY=$(op read op://Plug-App/production-rails-master-key/...) bin/rails credentials:edit -e production
29
+ fi
@@ -19,4 +19,4 @@ elsif options[:parse_string].present?
19
19
  end
20
20
 
21
21
  puts "Parsing `#{body}` into HMAC"
22
- puts OpenSSL::HMAC.hexdigest(Authable::SHA256_DIGEST, YETTO_PLUG_APP_TOKEN, body)
22
+ puts OpenSSL::HMAC.hexdigest(Authable::SHA256_DIGEST, SIGNING_SECRET, body)
@@ -1,51 +1,7 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
+ # This script is "symlink"ed from our actions repo.
3
+ # Not really, obviously, it's a real file.
2
4
 
3
5
  set -e
4
6
 
5
- function usage() {
6
- echo "Usage:"
7
- echo "$0 [options]"
8
- echo ""
9
- echo " Options:"
10
- echo " -u/--update Update license information"
11
- echo " -v/--verify Verify license information"
12
- echo " -g/--generate Generate CSV license data"
13
- echo " -h/--help Display this help message"
14
- echo ""
15
- exit 1
16
- }
17
-
18
- while [ "$1" != "" ]; do
19
- case $1 in
20
- -v | --verify)
21
- echo "Verifying dependency licenses ..."
22
- bin/bundle exec licensed env -c .licensed.yml
23
- bin/bundle exec licensed list -c .licensed.yml
24
- bin/bundle exec licensed status -c .licensed.yml
25
- RET=$?
26
- if [ $RET -ne 0 ]; then
27
- echo
28
- echo "*** When fixed, please run 'script/licenses -c' to update the license cache. ***"
29
- echo
30
- fi
31
-
32
- exit $RET
33
- ;;
34
- -u | --update)
35
- echo "Caching dependency licenses ..."
36
- bin/bundle exec licensed cache -c .licensed.yml
37
- ;;
38
- -g | --generate)
39
- echo "Generating CSV licenses ..."
40
- bin/bundle exec rake licenses:generate
41
- ;;
42
- -h | --help)
43
- usage
44
- ;;
45
- *)
46
- usage
47
- exit 1
48
- ;;
49
- esac
50
- shift
51
- done
7
+ ../actions/script/licenses "$@"
@@ -1,5 +1,65 @@
1
- #!/bin/sh
1
+ #!/usr/bin/env bash
2
2
 
3
3
  set -e
4
4
 
5
- bin/foreman start -f Procfile.dev
5
+ # Initialize flags
6
+ local_dev=true
7
+ api_only=false
8
+ debug=false
9
+
10
+ function opr_cmd() {
11
+ if $local_dev; then
12
+ bin/opr $1
13
+ else
14
+ $1
15
+ fi
16
+ }
17
+
18
+ function cleanup() {
19
+ echo "Cleaning up attached services..."
20
+ docker compose down
21
+ echo "...Done"
22
+ }
23
+
24
+ # Check for and parse flags
25
+ for arg in "$@"
26
+ do
27
+ case $arg in
28
+ --api-only)
29
+ api_only=true
30
+ ;;
31
+ --docker)
32
+ local_dev=false
33
+ ;;
34
+ --debug)
35
+ export DEBUG=true
36
+ debug=true
37
+ ;;
38
+ *)
39
+ # Unknown arguments can be ignored or handled here
40
+ ;;
41
+ esac
42
+ done
43
+
44
+ # In non-local dev scenarios, change ownership of the application to the non-root 'plug-app' user
45
+ if [[ $local_dev == false ]]; then
46
+ chown -R plug-app:plug-app /usr/src/app
47
+ else
48
+ # In local dev scenarios, run attached compose services in detached mode
49
+ docker compose up --wait
50
+ fi
51
+
52
+ if $local_dev; then
53
+
54
+ # Ensure docker-compose goes down when the server is stopped
55
+ trap cleanup SIGINT
56
+ trap cleanup SIGTSTP
57
+
58
+ if $debug; then
59
+ bin/foreman start -f Procfile.debug
60
+ else
61
+ bin/foreman start -f Procfile.dev
62
+ fi
63
+ else
64
+ bin/puma -C config/puma.rb
65
+ fi
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+ # This script is "symlink"ed from our actions repo.
3
+ # Not really, obviously, it's a real file.
4
+
5
+ set -e
6
+
7
+ ../actions/script/sorbet "$@"
@@ -0,0 +1,32 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ require "test_helper"
5
+
6
+ class ApplicationControllerTest < ActionDispatch::IntegrationTest
7
+ test "renders a 404" do
8
+ get "/asdasdasdasd"
9
+
10
+ assert_response :not_found
11
+ assert_match(/Not Found/, response.body)
12
+ end
13
+
14
+ test "bogus js does not 500" do
15
+ get "/js/admin.js"
16
+
17
+ assert_response :not_found
18
+ assert_match(/Not Found/, response.body)
19
+ end
20
+
21
+ test "bogus routes do not 500" do
22
+ post "/"
23
+
24
+ assert_response :not_found
25
+ assert_match(/Not Found/, response.body)
26
+
27
+ put "/asdads"
28
+
29
+ assert_response :not_found
30
+ assert_match(/Not Found/, response.body)
31
+ end
32
+ end
@@ -6,7 +6,7 @@ require "test_helper"
6
6
  class SettingsControllerTest < ActionDispatch::IntegrationTest
7
7
  include API::TestHelpers
8
8
 
9
- include Webmocks::Yetto
9
+ include Webmocks::YettoWebmock
10
10
 
11
11
  test "GET /settings without asking for JSON fails" do
12
12
  api(:get, "/settings", headers: nil)
@@ -6,7 +6,7 @@ require "test_helper"
6
6
  class YettoControllerTest < ActionDispatch::IntegrationTest
7
7
  include API::TestHelpers
8
8
 
9
- include Webmocks::Yetto
9
+ include Webmocks::YettoWebmock
10
10
 
11
11
  def setup
12
12
  super
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEpAIBAAKCAQEAljw3p40+fSF5QkoVWnof6J3UVH8NRu80CZWLK+FXH/yEzfZj
3
+ 5ZQdbLRZzbhd24PIqbyCKJe0JS82ya9AbElT7VkfTGrj/smqepgv1FuhxWsTYGSy
4
+ kIBST06mZGnzaOLzP0H2CEHZwQtIX3W9vgqBrUYu5RCz3zUI7z7MwE2J8lZ6I9hy
5
+ pUzPFK3FIAar8sgA0FNTK2I3P5MWUGwGW+8BiudpNz3dMMHJVQ7dRuNj/PazCv4p
6
+ DIF0ZSwzaqTP+XBaaLRAwOD24dZWbiJNLKR6l2CU/xpIABHqk6WoO7FZcfn2sI8c
7
+ Bey7YoJOvGe8+AB7MYPJ2IXOdgFihr4WVX74ZQIDAQABAoIBAQCEomc0KnOnv1yx
8
+ lHwjo7v1/xlM+9o57MbRS1BSDiCAIc0RlNx++/O6W8MI5yMdwMvwZne25K/rQDKr
9
+ fmhu8ZIB8nO6YIgnEd3LW/6mCbvZcf3qVRx8jH2efL5T2mJGEE9WYqKWiaR4VMCx
10
+ Xl6En/v6gQK3wrY6cjUQGy5i/FG0OyBIQZDucIc4b4TdLBUzo85xbXvodX9hWCvm
11
+ qGoZlrmKWxn/Ro+Hi0NJbKPR0DUAfQVBzg9QqJTVvQtdVeAnisgYVUUDKevFV7sm
12
+ jyryJ2vKzvPNOHYsBMD/bRlj1loHlpqIddEsBoxSeq8aNJ5nEz31qG7AHBLu+TK+
13
+ ZGILRnDhAoGBAMdiMSz1jrur55dDHoclciPFbKop6j/HmpU85LuMsi1nXejog9Bs
14
+ uir75boKgd3P51rbEruOPVZqf6bkPhO3da1YI2x8j0B+V/kDXbPLYPxfVmfOo/ct
15
+ cxBqXloe0036ZO96y/IJlRPvSY2H/mXiNCnGzej6ROgH4t+vR0iEl2/NAoGBAMDl
16
+ R9IRjdB4bemZEMAoeORpsD7esb0dLA7W7/ObJxBRFuUcQOJq/JNb7SYFdXrLAeUd
17
+ QWevXsS2ZjqmxlEWwGtqy0D548Rh4F3SpWiDh7hG3hePtC/XC57t00/cWYe2kTWQ
18
+ 0662y00qwsWCo4Uy++iIiNx44ilWhcE5phCowiL5AoGAUQKwgFf1eoNKQcdfrAGm
19
+ 8qnQkQMeznNHd8OaHCn6a0BIg82VYSYMLlLS8Fg8k+dZVS0V22bbvTTgUOsD3fb4
20
+ tUnOetHRUp8DF4YqmFbWPTRvYxYuwMuSqOTPGUbVDCXkxPjbzKfgDo13ES5kSvkx
21
+ wJeqKjMltDEgGUqaZ/iXnzECgYArMKs+G/QW44Aot78KZ4V6DzgJO6+sWmXNBM9B
22
+ SlIa0y0/K25TxAS9se2Nf9doISBRfpVwc9HSVczaARGSgnefFZBhAhK/m/Kyz0F9
23
+ /0VaO3Pq7qA3vfy6HyIbVYkuW/Bzf/QFwKQQqSxnMPMQFfRVgoyyYNayzs6wDwph
24
+ 3IdrcQKBgQC+VpUU/04AD9qFk+6GwXer69i3NQJ+LtYEsJ8yeKzS5MUOt3s+C2T6
25
+ uKLdq/j5XwzIIulcBQEJOoa1A3KcaIpkiWgvAbAKrirH9IobHvVLk9RxQ4EMihhU
26
+ /GBStICbD54zeJmrEJx+yxa4HYx/aKViPpt6xg3WJdBJplTmCq181g==
27
+ -----END RSA PRIVATE KEY-----
@@ -4,30 +4,15 @@
4
4
  require "test_helper"
5
5
 
6
6
  class UpdateYettoJobTest < ActiveJob::TestCase
7
- include Webmocks::Yetto
7
+ include Webmocks::YettoWebmock
8
8
 
9
9
  def setup
10
10
  super
11
11
 
12
12
  @update_installation_body = {
13
- plug_installation: {
14
- credentials: {},
15
- settings: {},
16
- },
13
+ credentials: {},
14
+ settings: {},
17
15
  }
18
-
19
- @installation_params = {
20
- type: "installation",
21
- inbox: {
22
- id: @inbox_id,
23
- },
24
- organization: {
25
- id: @organization_id,
26
- },
27
- }
28
-
29
- @installation_params[:plug_installation] = @update_installation_body[:plug_installation].dup
30
- @installation_params[:plug_installation][:id] = @plug_installation_id
31
16
  end
32
17
 
33
18
  test "does nothing if type is not supported" do
@@ -60,7 +60,7 @@ module API
60
60
  end
61
61
 
62
62
  def prepend_plug_path(version, path)
63
- "/${app}/#{version}#{path}"
63
+ "/app/#{version}#{path}"
64
64
  end
65
65
 
66
66
  def prepend_api_path(version, path)
@@ -32,7 +32,7 @@ module ActiveSupport
32
32
 
33
33
  expected_value = expected_args[actual_key]
34
34
 
35
- assert_equal(expected_value, actual_value)
35
+ assert_equal(expected_value, actual_value, "Expected `#{actual_key}` to be `#{expected_value.nil? ? "nil" : expected_value}`, but was `#{actual_value.nil? ? "nil" : actual_value}`")
36
36
  end
37
37
  end
38
38
  end
@@ -8,12 +8,12 @@ module Webmocks
8
8
 
9
9
  sig { returns(T.untyped) }
10
10
  def assert_requested_send_to_slack_log
11
- assert_requested(:post, "https://slack.com:80/the_log_room")
11
+ assert_requested(:post, "https://slack.com/the_log_room")
12
12
  end
13
13
 
14
14
  sig { returns(T.untyped) }
15
15
  def stub_send_to_slack_log
16
- stub_request(:post, "https://slack.com:80/the_log_room")
16
+ stub_request(:post, "https://slack.com/the_log_room")
17
17
  .to_return(
18
18
  status: 200,
19
19
  headers: { content_type: "application/json; charset=utf-8" },
@@ -0,0 +1,119 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ module Webmocks
5
+ module YettoWebmock
6
+ def yetto_auth_header(payload, signing_secret = "super-secret")
7
+ "sha256=#{OpenSSL::HMAC.hexdigest(Authable::SHA256_DIGEST, signing_secret, payload.to_json)}"
8
+ end
9
+
10
+ def assert_requested_post_access_token(plug_installation_id)
11
+ assert_requested(:post, "#{::YettoService::YETTO_API_VERSION_TLD}/plugs/installations/#{plug_installation_id}/access_tokens")
12
+ end
13
+
14
+ def stub_post_access_token(plug_installation_id)
15
+ response = {
16
+ token: Faker::Alphanumeric.alphanumeric(number: 26).upcase,
17
+ }
18
+ stub_request(:post, "#{::YettoService::YETTO_API_VERSION_TLD}/plugs/installations/#{plug_installation_id}/access_tokens")
19
+ .to_return(
20
+ body: response.to_json,
21
+ )
22
+ end
23
+
24
+ def assert_requested_get_plug_installation(plug_installation_id)
25
+ assert_requested_post_access_token(plug_installation_id)
26
+ assert_requested(:get, "#{::YettoService::YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}")
27
+ end
28
+
29
+ def stub_get_plug_installation(plug_installation_id, response = nil, status: 200)
30
+ stub_post_access_token(plug_installation_id)
31
+
32
+ response ||= {
33
+ installed_on_inbox: {
34
+ id: inbox_id,
35
+ organization: {
36
+ id: organization_id,
37
+ status: "active",
38
+ },
39
+ },
40
+ plug: {
41
+ id: "plg_#{Faker::Alphanumeric.alphanumeric(number: 26).upcase}",
42
+ },
43
+ settings: {
44
+ from_email: "new@from.company",
45
+ },
46
+ }
47
+
48
+ stub_request(:get, "#{::YettoService::YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}")
49
+ .to_return(
50
+ status: status,
51
+ headers: { content_type: "application/json; charset=utf-8" },
52
+ body: response.to_json,
53
+ )
54
+ end
55
+
56
+ def assert_requested_update_installation(plug_installation_id)
57
+ assert_requested_post_access_token(plug_installation_id)
58
+
59
+ assert_requested(:patch, "#{::YettoService::YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}")
60
+ end
61
+
62
+ def stub_update_installation(plug_installation_id, params, response: {}, status: 200)
63
+ stub_post_access_token(plug_installation_id)
64
+
65
+ stub_request(:patch, "#{::YettoService::YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}")
66
+ .with(
67
+ body: params,
68
+ )
69
+ .to_return(
70
+ status: status,
71
+ headers: { content_type: "application/json; charset=utf-8" },
72
+ body: response.to_json,
73
+ )
74
+ end
75
+
76
+ def assert_requested_create_message(inbox_id)
77
+ assert_requested_post_access_token(plug_installation_id)
78
+
79
+ assert_requested(:post, "#{::YettoService::YETTO_API_VERSION_TLD}/inboxes/#{inbox_id}/messages")
80
+ end
81
+
82
+ def stub_create_message(inbox_id, payload)
83
+ stub_post_access_token(plug_installation_id)
84
+
85
+ stub_request(:post, "#{::YettoService::YETTO_API_VERSION_TLD}/inboxes/#{inbox_id}/messages")
86
+ .with(
87
+ body: payload,
88
+ )
89
+ .to_return(
90
+ status: 200,
91
+ headers: { content_type: "application/json; charset=utf-8" },
92
+ body: {}.to_json,
93
+ )
94
+ end
95
+
96
+ def assert_requested_create_inbox_switch(inbox_id, plug_installation_id)
97
+ assert_requested_post_access_token(plug_installation_id)
98
+ assert_requested(:post, "#{::YettoService::YETTO_API_VERSION_TLD}/inboxes/#{inbox_id}/switches")
99
+ end
100
+
101
+ def stub_create_inbox_switch(inbox_id, plug_installation_id, params)
102
+ stub_post_access_token(plug_installation_id)
103
+
104
+ payload = {
105
+ name: "After install",
106
+ }
107
+
108
+ stub_request(:post, "#{::YettoService::YETTO_API_VERSION_TLD}/inboxes/#{inbox_id}/switches")
109
+ .with(
110
+ body: payload,
111
+ )
112
+ .to_return(
113
+ status: 200,
114
+ headers: { content_type: "application/json; charset=utf-8" },
115
+ body: {}.to_json,
116
+ )
117
+ end
118
+ end
119
+ end
@@ -3,15 +3,28 @@
3
3
 
4
4
  require "debug" if ENV.fetch("DEBUG", false)
5
5
 
6
+ if ENV["COVERAGE"] == "1"
7
+ require "simplecov"
8
+ require "simplecov-console"
9
+
10
+ SimpleCov.start("rails")
11
+
12
+ # do not crash on failure; we want a distinct job to report the coverage error
13
+ module SimpleCov
14
+ class << self
15
+ def result_exit_status(_)
16
+ SimpleCov::ExitCodes::SUCCESS
17
+ end
18
+ end
19
+ end
20
+ end
21
+
6
22
  require "httpx"
7
23
  require "webmock/minitest"
8
24
  require "httpx/adapters/webmock"
9
25
  WebMock.enable!
10
26
  WebMock.disable_net_connect!(allow_localhost: true)
11
27
 
12
- require "dotenv"
13
- Dotenv.load(".env.test")
14
-
15
28
  require_relative "./support/rails"
16
29
 
17
30
  require "minitest/pride"
@@ -0,0 +1,38 @@
1
+ # fly.toml app configuration file generated for plug-app on 2023-05-05T07:11:14-04:00
2
+ #
3
+ # See https://fly.io/docs/reference/configuration/ for information about how to use this file.
4
+ #
5
+
6
+ app = "plug-app-production"
7
+ primary_region = "iad"
8
+
9
+ [env]
10
+ RAILS_ENV = "production"
11
+ LD_PRELOAD_PATH = "/usr/lib/x86_64-linux-gnu/libjemalloc.so.2"
12
+
13
+ [processes]
14
+ web = "./bin/rails server"
15
+ worker = "bundle exec sidekiq"
16
+
17
+ [http_service]
18
+ internal_port = 3000
19
+ force_https = true
20
+ auto_stop_machines = true
21
+ auto_start_machines = true
22
+ min_machines_running = 1
23
+ processes = ["web"]
24
+ [http_service.concurrency]
25
+ type = "requests"
26
+ soft_limit = 200
27
+ hard_limit = 250
28
+
29
+ [checks]
30
+ [checks.alive]
31
+ type = "tcp"
32
+ interval = "15s"
33
+ timeout = "2s"
34
+ grace_period = "5s"
35
+
36
+ [[statics]]
37
+ guest_path = "/plug-app/public"
38
+ url_prefix = "/"
@@ -0,0 +1,33 @@
1
+ app = "plug-app-staging"
2
+ primary_region = "iad"
3
+
4
+ [env]
5
+ RAILS_ENV = "plug-app-staging"
6
+ LD_PRELOAD_PATH = "/usr/lib/x86_64-linux-gnu/libjemalloc.so.2"
7
+
8
+ [processes]
9
+ web = "./bin/rails server"
10
+ worker = "bundle exec sidekiq"
11
+
12
+ [http_service]
13
+ internal_port = 3000
14
+ force_https = true
15
+ auto_stop_machines = true
16
+ auto_start_machines = true
17
+ min_machines_running = 0
18
+ processes = ["web"]
19
+ [http_service.concurrency]
20
+ type = "requests"
21
+ soft_limit = 200
22
+ hard_limit = 250
23
+
24
+ [checks]
25
+ [checks.alive]
26
+ type = "tcp"
27
+ interval = "15s"
28
+ timeout = "2s"
29
+ grace_period = "5s"
30
+
31
+ [[statics]]
32
+ guest_path = "/plug-app/public"
33
+ url_prefix = "/"