hephaestus 0.1.3 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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 = "/"