uffizzi_core 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (240) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/README.md +46 -0
  4. data/Rakefile +31 -0
  5. data/app/assets/config/uffizzi_core_manifest.js +1 -0
  6. data/app/assets/stylesheets/uffizzi_core/application.css +15 -0
  7. data/app/clients/uffizzi_core/amazon_registry_client.rb +18 -0
  8. data/app/clients/uffizzi_core/azure_registry_client/request_result.rb +5 -0
  9. data/app/clients/uffizzi_core/azure_registry_client.rb +42 -0
  10. data/app/clients/uffizzi_core/controller_client/request_result.rb +5 -0
  11. data/app/clients/uffizzi_core/controller_client.rb +106 -0
  12. data/app/clients/uffizzi_core/docker_hub_client/request_result.rb +7 -0
  13. data/app/clients/uffizzi_core/docker_hub_client.rb +139 -0
  14. data/app/clients/uffizzi_core/github/app_client.rb +19 -0
  15. data/app/clients/uffizzi_core/github/installation_client.rb +11 -0
  16. data/app/clients/uffizzi_core/github/user_client.rb +51 -0
  17. data/app/clients/uffizzi_core/google_registry_client/request_result.rb +5 -0
  18. data/app/clients/uffizzi_core/google_registry_client.rb +42 -0
  19. data/app/contexts/uffizzi_core/base_context.rb +12 -0
  20. data/app/contexts/uffizzi_core/project_context.rb +13 -0
  21. data/app/contexts/uffizzi_core/webhooks_context.rb +9 -0
  22. data/app/controllers/concerns/uffizzi_core/auth_management.rb +23 -0
  23. data/app/controllers/concerns/uffizzi_core/authorization_concern.rb +38 -0
  24. data/app/controllers/concerns/uffizzi_core/dependency_injection_concern.rb +19 -0
  25. data/app/controllers/uffizzi_core/api/cli/v1/account/application_controller.rb +7 -0
  26. data/app/controllers/uffizzi_core/api/cli/v1/account/credentials_controller.rb +55 -0
  27. data/app/controllers/uffizzi_core/api/cli/v1/application_controller.rb +5 -0
  28. data/app/controllers/uffizzi_core/api/cli/v1/projects/application_controller.rb +11 -0
  29. data/app/controllers/uffizzi_core/api/cli/v1/projects/compose_files_controller.rb +93 -0
  30. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/activity_items_controller.rb +36 -0
  31. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/application_controller.rb +7 -0
  32. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/containers/application_controller.rb +8 -0
  33. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/containers/logs_controller.rb +27 -0
  34. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/containers_controller.rb +24 -0
  35. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/events_controller.rb +29 -0
  36. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments_controller.rb +148 -0
  37. data/app/controllers/uffizzi_core/api/cli/v1/projects/secrets_controller.rb +69 -0
  38. data/app/controllers/uffizzi_core/api/cli/v1/projects_controller.rb +19 -0
  39. data/app/controllers/uffizzi_core/api/cli/v1/sessions_controller.rb +43 -0
  40. data/app/controllers/uffizzi_core/application_controller.rb +51 -0
  41. data/app/errors/uffizzi_core/compose_file/build_error.rb +4 -0
  42. data/app/errors/uffizzi_core/compose_file/credential_error.rb +4 -0
  43. data/app/errors/uffizzi_core/compose_file/not_found_error.rb +4 -0
  44. data/app/errors/uffizzi_core/compose_file/parse_error.rb +4 -0
  45. data/app/errors/uffizzi_core/compose_file/secrets_error.rb +4 -0
  46. data/app/errors/uffizzi_core/deployment_not_found_error.rb +10 -0
  47. data/app/forms/uffizzi_core/api/cli/v1/account/credential/create_form.rb +26 -0
  48. data/app/forms/uffizzi_core/api/cli/v1/compose_file/check_credentials_form.rb +21 -0
  49. data/app/forms/uffizzi_core/api/cli/v1/compose_file/cli_form.rb +39 -0
  50. data/app/forms/uffizzi_core/api/cli/v1/compose_file/create_form.rb +13 -0
  51. data/app/forms/uffizzi_core/api/cli/v1/compose_file/template_form.rb +44 -0
  52. data/app/forms/uffizzi_core/api/cli/v1/compose_file/update_form.rb +9 -0
  53. data/app/forms/uffizzi_core/api/cli/v1/config_file/create_form.rb +11 -0
  54. data/app/forms/uffizzi_core/api/cli/v1/deployment/create_form.rb +91 -0
  55. data/app/forms/uffizzi_core/api/cli/v1/project/delete_secret_form.rb +27 -0
  56. data/app/forms/uffizzi_core/api/cli/v1/project/update_form.rb +40 -0
  57. data/app/forms/uffizzi_core/api/cli/v1/session_create_form.rb +29 -0
  58. data/app/forms/uffizzi_core/api/cli/v1/template/create_form.rb +65 -0
  59. data/app/forms/uffizzi_core/application_form.rb +11 -0
  60. data/app/forms/uffizzi_core/application_form_without_active_record.rb +17 -0
  61. data/app/forms/uffizzi_core/mass_assignment_control_concern.rb +22 -0
  62. data/app/helpers/uffizzi_core/application_helper.rb +6 -0
  63. data/app/jobs/uffizzi_core/account/create_credential_job.rb +10 -0
  64. data/app/jobs/uffizzi_core/activity_item/docker/update_digest_job.rb +11 -0
  65. data/app/jobs/uffizzi_core/application_job.rb +7 -0
  66. data/app/jobs/uffizzi_core/config_file/apply_job.rb +31 -0
  67. data/app/jobs/uffizzi_core/credential/docker_hub/create_webhook_job.rb +15 -0
  68. data/app/jobs/uffizzi_core/deployment/create_credential_job.rb +32 -0
  69. data/app/jobs/uffizzi_core/deployment/create_credentials_job.rb +17 -0
  70. data/app/jobs/uffizzi_core/deployment/create_job.rb +15 -0
  71. data/app/jobs/uffizzi_core/deployment/create_webhooks_job.rb +13 -0
  72. data/app/jobs/uffizzi_core/deployment/delete_credential_job.rb +13 -0
  73. data/app/jobs/uffizzi_core/deployment/delete_job.rb +11 -0
  74. data/app/jobs/uffizzi_core/deployment/deploy_containers_job.rb +27 -0
  75. data/app/jobs/uffizzi_core/deployment/manage_deploy_activity_item_job.rb +19 -0
  76. data/app/jobs/uffizzi_core/deployment/send_github_preview_message_job.rb +13 -0
  77. data/app/lib/uffizzi_core/rbac/user_access_service.rb +21 -0
  78. data/app/mailers/uffizzi_core/application_mailer.rb +8 -0
  79. data/app/models/concerns/uffizzi_core/hashid_concern.rb +25 -0
  80. data/app/models/concerns/uffizzi_core/state_machine_concern.rb +16 -0
  81. data/app/models/uffizzi_core/account.rb +101 -0
  82. data/app/models/uffizzi_core/activity_item/docker.rb +4 -0
  83. data/app/models/uffizzi_core/activity_item/github.rb +4 -0
  84. data/app/models/uffizzi_core/activity_item/memory_limit.rb +4 -0
  85. data/app/models/uffizzi_core/activity_item.rb +58 -0
  86. data/app/models/uffizzi_core/application_record.rb +7 -0
  87. data/app/models/uffizzi_core/build.rb +39 -0
  88. data/app/models/uffizzi_core/comment.rb +16 -0
  89. data/app/models/uffizzi_core/compose_file.rb +57 -0
  90. data/app/models/uffizzi_core/config_file.rb +24 -0
  91. data/app/models/uffizzi_core/container.rb +100 -0
  92. data/app/models/uffizzi_core/container_config_file.rb +8 -0
  93. data/app/models/uffizzi_core/continuous_preview.rb +4 -0
  94. data/app/models/uffizzi_core/coupon.rb +5 -0
  95. data/app/models/uffizzi_core/credential/amazon.rb +4 -0
  96. data/app/models/uffizzi_core/credential/azure.rb +4 -0
  97. data/app/models/uffizzi_core/credential/docker_hub.rb +4 -0
  98. data/app/models/uffizzi_core/credential/github.rb +4 -0
  99. data/app/models/uffizzi_core/credential/google.rb +4 -0
  100. data/app/models/uffizzi_core/credential.rb +64 -0
  101. data/app/models/uffizzi_core/database.rb +4 -0
  102. data/app/models/uffizzi_core/database_offering.rb +4 -0
  103. data/app/models/uffizzi_core/deployment.rb +77 -0
  104. data/app/models/uffizzi_core/event.rb +13 -0
  105. data/app/models/uffizzi_core/invitation.rb +27 -0
  106. data/app/models/uffizzi_core/membership.rb +16 -0
  107. data/app/models/uffizzi_core/payment.rb +11 -0
  108. data/app/models/uffizzi_core/price.rb +9 -0
  109. data/app/models/uffizzi_core/product.rb +11 -0
  110. data/app/models/uffizzi_core/project.rb +66 -0
  111. data/app/models/uffizzi_core/rating.rb +20 -0
  112. data/app/models/uffizzi_core/repo/amazon.rb +4 -0
  113. data/app/models/uffizzi_core/repo/azure.rb +4 -0
  114. data/app/models/uffizzi_core/repo/docker_hub.rb +4 -0
  115. data/app/models/uffizzi_core/repo/github.rb +4 -0
  116. data/app/models/uffizzi_core/repo/google.rb +4 -0
  117. data/app/models/uffizzi_core/repo.rb +39 -0
  118. data/app/models/uffizzi_core/role.rb +17 -0
  119. data/app/models/uffizzi_core/template.rb +19 -0
  120. data/app/models/uffizzi_core/user.rb +62 -0
  121. data/app/models/uffizzi_core/user_project.rb +14 -0
  122. data/app/policies/uffizzi_core/api/cli/v1/account/credentials_policy.rb +11 -0
  123. data/app/policies/uffizzi_core/api/cli/v1/projects/compose_files_policy.rb +15 -0
  124. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments/activity_items_policy.rb +7 -0
  125. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments/containers_policy.rb +7 -0
  126. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments/events_policy.rb +7 -0
  127. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments_policy.rb +23 -0
  128. data/app/policies/uffizzi_core/api/cli/v1/projects/secrets_policy.rb +15 -0
  129. data/app/policies/uffizzi_core/api/cli/v1/projects_policy.rb +7 -0
  130. data/app/policies/uffizzi_core/application_policy.rb +12 -0
  131. data/app/repositories/uffizzi_core/activity_item_repo.rb +9 -0
  132. data/app/repositories/uffizzi_core/basic_order_repo.rb +11 -0
  133. data/app/repositories/uffizzi_core/build_repo.rb +23 -0
  134. data/app/repositories/uffizzi_core/comment_repo.rb +11 -0
  135. data/app/repositories/uffizzi_core/compose_file_repo.rb +11 -0
  136. data/app/repositories/uffizzi_core/config_file_repo.rb +40 -0
  137. data/app/repositories/uffizzi_core/container_repo.rb +25 -0
  138. data/app/repositories/uffizzi_core/credential_repo.rb +36 -0
  139. data/app/repositories/uffizzi_core/deployment_repo.rb +23 -0
  140. data/app/repositories/uffizzi_core/event_repo.rb +9 -0
  141. data/app/repositories/uffizzi_core/membership_repo.rb +10 -0
  142. data/app/repositories/uffizzi_core/price_repo.rb +11 -0
  143. data/app/repositories/uffizzi_core/product_repo.rb +11 -0
  144. data/app/repositories/uffizzi_core/project_repo.rb +10 -0
  145. data/app/repositories/uffizzi_core/repo_repo.rb +10 -0
  146. data/app/repositories/uffizzi_core/template_repo.rb +87 -0
  147. data/app/repositories/uffizzi_core/usage_repo.rb +9 -0
  148. data/app/repositories/uffizzi_core/user_repo.rb +11 -0
  149. data/app/responders/uffizzi_core/json_responder.rb +13 -0
  150. data/app/serializers/uffizzi_core/api/cli/v1/account/credential_serializer.rb +9 -0
  151. data/app/serializers/uffizzi_core/api/cli/v1/project_serializer.rb +7 -0
  152. data/app/serializers/uffizzi_core/api/cli/v1/projects/compose_file_serializer.rb +7 -0
  153. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer/container_serializer.rb +23 -0
  154. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer/user_serializer.rb +11 -0
  155. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer.rb +74 -0
  156. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/activity_item_serializer.rb +24 -0
  157. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/container_serializer/container_config_file_serializer/config_file_serializer.rb +6 -0
  158. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/container_serializer/container_config_file_serializer.rb +7 -0
  159. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/container_serializer.rb +30 -0
  160. data/app/serializers/uffizzi_core/api/cli/v1/user_serializer/account_serializer.rb +5 -0
  161. data/app/serializers/uffizzi_core/api/cli/v1/user_serializer.rb +7 -0
  162. data/app/serializers/uffizzi_core/base_serializer.rb +7 -0
  163. data/app/serializers/uffizzi_core/controller/create_credential/credential_serializer.rb +17 -0
  164. data/app/serializers/uffizzi_core/controller/create_deployment/deployment_serializer.rb +5 -0
  165. data/app/serializers/uffizzi_core/controller/deploy_containers/container_serializer.rb +53 -0
  166. data/app/serializers/uffizzi_core/controller/deploy_containers/credential_serializer.rb +5 -0
  167. data/app/services/uffizzi_core/account_service.rb +21 -0
  168. data/app/services/uffizzi_core/activity_item_service.rb +98 -0
  169. data/app/services/uffizzi_core/amazon/credential_service.rb +31 -0
  170. data/app/services/uffizzi_core/amazon_service.rb +45 -0
  171. data/app/services/uffizzi_core/azure/credential_service.rb +18 -0
  172. data/app/services/uffizzi_core/cli/compose_file_service.rb +203 -0
  173. data/app/services/uffizzi_core/compose_file/builders/config_files_builder_service.rb +31 -0
  174. data/app/services/uffizzi_core/compose_file/builders/container_builder_service.rb +225 -0
  175. data/app/services/uffizzi_core/compose_file/builders/docker_repo_builder_service.rb +25 -0
  176. data/app/services/uffizzi_core/compose_file/builders/github_repo_builder_service.rb +59 -0
  177. data/app/services/uffizzi_core/compose_file/builders/template_builder_service.rb +45 -0
  178. data/app/services/uffizzi_core/compose_file/builders/variables_builder_service.rb +58 -0
  179. data/app/services/uffizzi_core/compose_file/config_files_service.rb +52 -0
  180. data/app/services/uffizzi_core/compose_file/config_option_service.rb +37 -0
  181. data/app/services/uffizzi_core/compose_file/configs_options_service.rb +26 -0
  182. data/app/services/uffizzi_core/compose_file/container_service.rb +64 -0
  183. data/app/services/uffizzi_core/compose_file/continuous_preview_options_service.rb +57 -0
  184. data/app/services/uffizzi_core/compose_file/dependencies_service.rb +55 -0
  185. data/app/services/uffizzi_core/compose_file/errors_service.rb +46 -0
  186. data/app/services/uffizzi_core/compose_file/github_dependencies_service.rb +38 -0
  187. data/app/services/uffizzi_core/compose_file/ingress_options_service.rb +49 -0
  188. data/app/services/uffizzi_core/compose_file/secrets_options_service.rb +28 -0
  189. data/app/services/uffizzi_core/compose_file/services_options/build_service.rb +93 -0
  190. data/app/services/uffizzi_core/compose_file/services_options/command_service.rb +18 -0
  191. data/app/services/uffizzi_core/compose_file/services_options/configs_service.rb +51 -0
  192. data/app/services/uffizzi_core/compose_file/services_options/deploy_service.rb +44 -0
  193. data/app/services/uffizzi_core/compose_file/services_options/entrypoint_service.rb +18 -0
  194. data/app/services/uffizzi_core/compose_file/services_options/env_file_service.rb +34 -0
  195. data/app/services/uffizzi_core/compose_file/services_options/environment_service.rb +20 -0
  196. data/app/services/uffizzi_core/compose_file/services_options/image_service.rb +89 -0
  197. data/app/services/uffizzi_core/compose_file/services_options/secrets_service.rb +35 -0
  198. data/app/services/uffizzi_core/compose_file/services_options_service.rb +55 -0
  199. data/app/services/uffizzi_core/compose_file/template_service.rb +55 -0
  200. data/app/services/uffizzi_core/compose_file/update_service.rb +29 -0
  201. data/app/services/uffizzi_core/compose_file/variables_service.rb +25 -0
  202. data/app/services/uffizzi_core/compose_file_service.rb +33 -0
  203. data/app/services/uffizzi_core/container_service.rb +57 -0
  204. data/app/services/uffizzi_core/controller_service.rb +80 -0
  205. data/app/services/uffizzi_core/credential_service.rb +44 -0
  206. data/app/services/uffizzi_core/deployment_service.rb +274 -0
  207. data/app/services/uffizzi_core/docker_hub/credential_service.rb +15 -0
  208. data/app/services/uffizzi_core/docker_hub_service.rb +77 -0
  209. data/app/services/uffizzi_core/github/app_service.rb +51 -0
  210. data/app/services/uffizzi_core/github/credential_service.rb +124 -0
  211. data/app/services/uffizzi_core/github/message_service.rb +20 -0
  212. data/app/services/uffizzi_core/github_service.rb +28 -0
  213. data/app/services/uffizzi_core/google/credential_service.rb +18 -0
  214. data/app/services/uffizzi_core/logs_service.rb +33 -0
  215. data/app/services/uffizzi_core/manage_activity_items_service.rb +166 -0
  216. data/app/services/uffizzi_core/project_service.rb +38 -0
  217. data/app/services/uffizzi_core/repo_service.rb +178 -0
  218. data/app/services/uffizzi_core/response_service.rb +13 -0
  219. data/app/services/uffizzi_core/template_service.rb +21 -0
  220. data/app/services/uffizzi_core/token_service.rb +19 -0
  221. data/app/services/uffizzi_core/user_access_service.rb +14 -0
  222. data/app/utils/uffizzi_core/converters.rb +33 -0
  223. data/app/validators/uffizzi_core/email_validator.rb +9 -0
  224. data/app/validators/uffizzi_core/environment_variable_list_validator.rb +15 -0
  225. data/app/validators/uffizzi_core/image_command_args_validator.rb +21 -0
  226. data/config/initializers/rswag_api.rb +15 -0
  227. data/config/initializers/rswag_ui.rb +15 -0
  228. data/config/initializers/swagger_yard.rb +17 -0
  229. data/config/locales/en.activerecord.yml +18 -0
  230. data/config/locales/en.yml +61 -0
  231. data/config/routes.rb +55 -0
  232. data/db/migrate/20220218121438_create_uffizzi_core_tables.rb +375 -0
  233. data/db/migrate/20220325113342_add_name_to_uffizzi_containers.rb +7 -0
  234. data/db/seeds.rb +16 -0
  235. data/lib/tasks/uffizzi_core_tasks.rake +14 -0
  236. data/lib/uffizzi_core/engine.rb +15 -0
  237. data/lib/uffizzi_core/version.rb +5 -0
  238. data/lib/uffizzi_core.rb +60 -0
  239. data/swagger/v1/swagger.json +1278 -0
  240. metadata +935 -0
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::DependenciesService
4
+ ENV_FILE_TYPE = 'env_file'
5
+ CONFIG_TYPE = 'config'
6
+ class << self
7
+ def build_dependencies(compose_data, compose_path, dependencies_params)
8
+ dependencies = compose_data[:containers].map do |container|
9
+ env_file_dependencies = build_env_files_dependencies(container, compose_path, dependencies_params)
10
+ configs_dependencies = build_configs_dependencies(container, compose_path, dependencies_params)
11
+
12
+ env_file_dependencies + configs_dependencies
13
+ end
14
+
15
+ dependencies.compact.flatten
16
+ end
17
+
18
+ def build_env_files_dependencies(container, compose_path, dependencies_params)
19
+ env_files = container[:env_file]
20
+ return [] unless env_files.present?
21
+
22
+ env_files.map do |path|
23
+ dependency = dependencies_params.detect { |item| item[:path] == path }
24
+ source = build_source_path(compose_path, path)
25
+
26
+ base_file_params(dependency, container).merge(source: source, type: ENV_FILE_TYPE)
27
+ end
28
+ end
29
+
30
+ def build_configs_dependencies(container, compose_path, dependencies_params)
31
+ configs = container[:configs]
32
+ return [] unless configs.present?
33
+
34
+ configs.map do |config|
35
+ dependency = dependencies_params.detect { |item| item[:path] == config[:source] }
36
+ source = build_source_path(compose_path, dependency[:path])
37
+
38
+ base_file_params(dependency, container).merge(source: source, type: CONFIG_TYPE)
39
+ end
40
+ end
41
+
42
+ def base_file_params(dependency, container)
43
+ {
44
+ content: dependency[:content],
45
+ path: dependency[:path],
46
+ container_name: container[:container_name],
47
+ }
48
+ end
49
+
50
+ def build_source_path(compose_path, dependency_path)
51
+ prepared_compose_path = Pathname.new(compose_path).basename.to_s
52
+ "#{prepared_compose_path}/#{dependency_path}"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ErrorsService
4
+ SECRETS_ERROR_KEY = 'secret_variables'
5
+ class << self
6
+ def has_error?(compose_file, error_code)
7
+ error = compose_file.payload.dig('errors', error_code)
8
+
9
+ error.present?
10
+ end
11
+
12
+ def has_errors?(compose_file)
13
+ compose_file.payload['errors'].present?
14
+ end
15
+
16
+ def update_compose_errors!(compose_file, errors, invalid_content)
17
+ compose_file.payload['errors'] = errors
18
+ compose_file.set_invalid if compose_file.valid_file?
19
+ compose_file.content = invalid_content
20
+
21
+ compose_file.save!
22
+
23
+ compose_file
24
+ end
25
+
26
+ def reset_compose_errors!(compose_file)
27
+ compose_file.payload['errors'] = nil
28
+ compose_file.set_valid
29
+
30
+ compose_file.save!
31
+
32
+ compose_file
33
+ end
34
+
35
+ def reset_error!(compose_file, error_code)
36
+ errors = compose_file.payload['errors']
37
+ return if errors.nil?
38
+
39
+ new_errors = errors.except(error_code)
40
+ compose_file.payload['errors'] = new_errors
41
+ compose_file.save!
42
+
43
+ compose_file
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::GithubDependenciesService
4
+ ENV_FILE_TYPE = 'env_file'
5
+ CONFIG_TYPE = 'config'
6
+
7
+ class << self
8
+ def filename(dependency)
9
+ pathname = Pathname.new(dependency[:path])
10
+
11
+ pathname.basename.to_s
12
+ end
13
+
14
+ def content(dependency)
15
+ Base64.decode64(dependency[:content])
16
+ end
17
+
18
+ def env_file_dependencies_for_container(dependencies, container_name)
19
+ dependencies.select { |dependency| dependency[:type] == ENV_FILE_TYPE && dependency[:container_name] == container_name }
20
+ end
21
+
22
+ def configs_dependencies_for_container(dependencies, container_name)
23
+ configs_dependencies(dependencies).select { |dependency| dependency[:container_name] == container_name }
24
+ end
25
+
26
+ def configs_dependencies(dependencies)
27
+ dependencies.select { |dependency| dependency[:type] == CONFIG_TYPE }
28
+ end
29
+
30
+ def build_source_path(compose_path, dependency_path, repository_id, branch)
31
+ prepared_compose_path = Pathname.new(compose_path).basename.to_s
32
+ base_source = "#{prepared_compose_path}/#{dependency_path}"
33
+ return base_source if repository_id.blank?
34
+
35
+ "#{repository_id}/#{branch}/#{base_source}"
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::IngressOptionsService
4
+ class << self
5
+ def parse(ingress_data, services_data)
6
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.no_ingress') if ingress_data.nil?
7
+
8
+ container_name = container_name(ingress_data, services_data)
9
+ port = port(ingress_data)
10
+
11
+ {
12
+ container_name: container_name,
13
+ port: port,
14
+ }
15
+ end
16
+
17
+ private
18
+
19
+ def container_name(ingress_data, services_data)
20
+ container_name = ingress_data['service']
21
+
22
+ if container_name.nil?
23
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.ingress_service_not_found')
24
+ end
25
+
26
+ unless services_data.keys.include?(container_name)
27
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_ingress_service', value: container_name)
28
+ end
29
+
30
+ container_name
31
+ end
32
+
33
+ def port(ingress_data)
34
+ port = ingress_data['port']
35
+
36
+ if port.nil?
37
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.ingress_port_not_specified')
38
+ end
39
+
40
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_integer', option: :port) unless port.is_a?(Integer)
41
+
42
+ if port < Settings.compose.port_min_value || port > Settings.compose.port_max_value
43
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_port')
44
+ end
45
+
46
+ port
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::SecretsOptionsService
4
+ class << self
5
+ def parse(secrets_data)
6
+ return [] if secrets_data.nil?
7
+
8
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_type', option: :secrets) unless secrets_data.is_a?(Hash)
9
+
10
+ secrets = []
11
+ secrets_data.each_pair do |secret_name, secret_data|
12
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.secret_name_blank', option: secret_name) if secret_data['name'].blank?
13
+
14
+ if secret_data['external'] != true
15
+ raise UffizziCore::ComposeFile::ParseError,
16
+ I18n.t('compose.secret_external', secret: secret_name)
17
+ end
18
+
19
+ secrets << {
20
+ secret_name: secret_name,
21
+ secret_variable: secret_data['name'],
22
+ }
23
+ end
24
+
25
+ secrets
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::BuildService
4
+ extend UffizziCore::ComposeFile::VariablesService
5
+
6
+ class << self
7
+ def parse(build_data, compose_payload)
8
+ return {} if build_data.blank?
9
+
10
+ args = parse_args(build_data)
11
+
12
+ repository_url, branch, dockerfile_context_path = parse_context(build_data, compose_payload)
13
+ repository_parts = repository_url.split('/').last(2)
14
+ account_name = repository_parts.first
15
+ repository_name = repository_parts.last
16
+ dockerfile = build_data['dockerfile'].blank? ? ::Settings.compose.dockerfile_default_path : build_data['dockerfile']
17
+
18
+ {
19
+ repository_url: repository_url,
20
+ account_name: account_name,
21
+ repository_name: repository_name,
22
+ branch: branch,
23
+ dockerfile: dockerfile,
24
+ dockerfile_context_path: dockerfile_context_path,
25
+ args: args,
26
+ }
27
+ end
28
+
29
+ private
30
+
31
+ def parse_args(build_data)
32
+ args = build_data['args']
33
+ return [] if args.nil?
34
+
35
+ case args
36
+ when Array
37
+ args.map { |arg| parse_variable_from_string(arg) }
38
+ when Hash
39
+ args.to_a.map { |arg| parse_variable_from_array(arg) }
40
+ else
41
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_type', option: :args)
42
+ end
43
+ end
44
+
45
+ def parse_context(build_data, compose_payload)
46
+ if build_data.is_a?(String)
47
+ parse_context_from_inline_syntax(build_data, compose_payload)
48
+ else
49
+ parse_context_from_long_syntax(build_data, compose_payload)
50
+ end
51
+ end
52
+
53
+ def parse_repository_url_fragment(fragment)
54
+ branch, dockerfile_context_path = fragment.split(':')
55
+
56
+ [branch, dockerfile_context_path]
57
+ end
58
+
59
+ def valid_url?(url)
60
+ URI(url).host.present? && URI(url).host =~ /\w+\.\w+/ && URI(url).path.present?
61
+ end
62
+
63
+ def parse_context_from_inline_syntax(context, compose_payload)
64
+ if compose_payload[:repository_url].blank?
65
+ raise UffizziCore::ComposeFile::ParseError,
66
+ I18n.t('compose.build_context_unknown_repository')
67
+ end
68
+
69
+ repository_url = compose_payload[:repository_url]
70
+ branch = compose_payload[:branch]
71
+ dockerfile_context_path = UffizziCore::ComposeFile::ConfigOptionService.prepare_file_path_value(context)
72
+
73
+ [repository_url, branch, dockerfile_context_path]
74
+ end
75
+
76
+ def parse_context_from_long_syntax(build_data, compose_payload)
77
+ context = build_data['context']
78
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.build_context_no_specified') if context.blank?
79
+
80
+ if valid_url?(context)
81
+ uri = URI(context)
82
+ repository_url = "#{uri.scheme}://#{uri.host}#{uri.path}"
83
+ branch, dockerfile_context_path = parse_repository_url_fragment(uri.fragment.to_s)
84
+ else
85
+ repository_url, branch, dockerfile_context_path = parse_context_from_inline_syntax(context, compose_payload)
86
+ end
87
+
88
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_context', value: context) if repository_url.blank?
89
+
90
+ [repository_url, branch, dockerfile_context_path]
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::CommandService
4
+ class << self
5
+ def parse(command_data)
6
+ return nil if command_data.blank?
7
+
8
+ case command_data
9
+ when String
10
+ [command_data]
11
+ when Array
12
+ command_data
13
+ else
14
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_type', option: :command)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::ConfigsService
4
+ class << self
5
+ def parse(configs, global_configs_data)
6
+ return [] if configs.nil?
7
+
8
+ configs.map do |config|
9
+ config_data = case config
10
+ when String
11
+ process_short_syntax(config, global_configs_data)
12
+ when Hash
13
+ process_long_syntax(config, global_configs_data)
14
+ else
15
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_type', option: :configs)
16
+ end
17
+
18
+ config_data
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def process_short_syntax(config_name, global_configs_data)
25
+ global_config = find_global_config!(config_name, global_configs_data)
26
+
27
+ {
28
+ source: UffizziCore::ComposeFile::ConfigOptionService.prepare_file_path_value(global_config[:config_file]),
29
+ target: global_config[:config_file],
30
+ }
31
+ end
32
+
33
+ def process_long_syntax(config_data, global_configs_data)
34
+ global_config = find_global_config!(config_data['source'], global_configs_data)
35
+ target = config_data['target'].blank? ? global_config[:config_file] : config_data['target']
36
+
37
+ {
38
+ source: UffizziCore::ComposeFile::ConfigOptionService.prepare_file_path_value(global_config[:config_file]),
39
+ target: target,
40
+ }
41
+ end
42
+
43
+ def find_global_config!(config_name, global_configs_data)
44
+ detected_config = global_configs_data.detect { |global_config_data| global_config_data[:config_name] == config_name }
45
+
46
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.global_config_not_found', config: config_name) if detected_config.nil?
47
+
48
+ detected_config
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::DeployService
4
+ class << self
5
+ def parse(deploy_data)
6
+ return {} if deploy_data.blank?
7
+
8
+ auto = prepare_deploy_auto(deploy_data)
9
+ memory = prepare_memory(deploy_data)
10
+
11
+ {
12
+ auto: auto,
13
+ memory: memory,
14
+ }
15
+ end
16
+
17
+ private
18
+
19
+ def prepare_deploy_auto(deploy_data)
20
+ auto = deploy_data['x-uffizzi-auto-deploy-updates']
21
+ return auto if auto.nil? || auto.in?([true, false])
22
+
23
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_bool_value', field: :auto, value: auto)
24
+ end
25
+
26
+ def prepare_memory(deploy_data)
27
+ memory = deploy_data.dig('resources', 'limits', 'memory')
28
+ return nil if memory.blank?
29
+
30
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_memory_type', value: memory) unless memory.is_a?(String)
31
+
32
+ value, postfix = memory.scan(/^([0-9]+)([a-zA-Z]+)$/).flatten
33
+
34
+ if postfix.nil? || !Settings.compose.memory_postfixes.include?(postfix.downcase)
35
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_memory_postfix', value: memory)
36
+ end
37
+
38
+ {
39
+ value: value.to_i,
40
+ postfix: postfix.downcase,
41
+ }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::EntrypointService
4
+ class << self
5
+ def parse(entrypoint_data)
6
+ return nil if entrypoint_data.blank?
7
+
8
+ case entrypoint_data
9
+ when String
10
+ [entrypoint_data]
11
+ when Array
12
+ entrypoint_data
13
+ else
14
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_type', option: :entrypoint)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::EnvFileService
4
+ class << self
5
+ def parse(env_file)
6
+ env_files = case env_file
7
+ when String
8
+ [prepare_file_path(env_file)]
9
+ when Array
10
+ env_file.map { |env_file_path| prepare_file_path(env_file_path) }
11
+ else
12
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_type', option: :env_file)
13
+ end
14
+
15
+ check_duplicates(env_files)
16
+
17
+ env_files
18
+ end
19
+
20
+ private
21
+
22
+ def prepare_file_path(env_file_path)
23
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.empty_env_file') if env_file_path.blank?
24
+
25
+ UffizziCore::ComposeFile::ConfigOptionService.prepare_file_path_value(env_file_path)
26
+ end
27
+
28
+ def check_duplicates(env_files)
29
+ return if env_files.uniq.length == env_files.length
30
+
31
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.env_file_duplicates', values: env_files)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::EnvironmentService
4
+ extend UffizziCore::ComposeFile::VariablesService
5
+
6
+ class << self
7
+ def parse(environment)
8
+ return [] if environment.blank?
9
+
10
+ case environment
11
+ when Array
12
+ environment.map { |variable| parse_variable_from_string(variable) }
13
+ when Hash
14
+ environment.to_a.map { |variable| parse_variable_from_array(variable) }
15
+ else
16
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_type', option: :environment)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::ImageService
4
+ class << self
5
+ def parse(image)
6
+ return {} if image.blank?
7
+
8
+ image_parts = image.downcase.split(':')
9
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_image_value', value: image) if image_parts.count > 2
10
+
11
+ image_name, tag = image_parts
12
+ tag = Settings.compose.default_tag if tag.blank?
13
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_image_value', value: image) if image_name.blank?
14
+
15
+ if valid_image_url?(image_name)
16
+ url, namespace, name = parse_image_url(image_name)
17
+ else
18
+ namespace, name = parse_docker_hub_image(image_name)
19
+ end
20
+
21
+ {
22
+ registry_url: url,
23
+ namespace: namespace,
24
+ name: name,
25
+ tag: tag,
26
+ }
27
+ end
28
+
29
+ private
30
+
31
+ def valid_image_url?(image_name)
32
+ url = prepare_image_url(image_name)
33
+
34
+ URI(url).host.present? && URI(url).host =~ /\w+\.\w+/ && URI(url).path.present?
35
+ end
36
+
37
+ def prepare_image_url(image_name)
38
+ if image_name.start_with?('https://')
39
+ image_name
40
+ else
41
+ "https://#{image_name}"
42
+ end
43
+ end
44
+
45
+ def parse_image_url(image_name)
46
+ prepared_url = prepare_image_url(image_name)
47
+
48
+ uri = URI(prepared_url)
49
+ url = uri.host
50
+ path = uri.path.delete_suffix('/').delete_prefix('/')
51
+
52
+ namespace, name = parse_image_path(path)
53
+
54
+ [url, namespace, name]
55
+ end
56
+
57
+ def parse_image_path(path)
58
+ path_parts = path.split('/', 2)
59
+
60
+ if path_parts.count == 1
61
+ namespace = nil
62
+ name = path_parts.first
63
+ else
64
+ namespace = path_parts.first
65
+ name = path_parts.last
66
+ end
67
+
68
+ [namespace, name]
69
+ end
70
+
71
+ def parse_docker_hub_image(image_name)
72
+ if contains_account_name?(image_name)
73
+ namespace = image_name.split('/').first
74
+ name = image_name.split('/', 2).last.delete_suffix('/')
75
+ else
76
+ namespace = Settings.docker_hub.public_namespace
77
+ name = image_name
78
+ end
79
+
80
+ [namespace, name]
81
+ end
82
+
83
+ def contains_account_name?(image_name)
84
+ image_name_parts = image_name.split('/')
85
+
86
+ image_name_parts.count > 1
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptions::SecretsService
4
+ class << self
5
+ def parse(secrets, global_secrets_data)
6
+ return [] if secrets.nil?
7
+
8
+ secrets.map do |secret|
9
+ variable_name = if secret.is_a?(String)
10
+ process_short_syntax(secret, global_secrets_data)
11
+ else
12
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.invalid_type', option: :secrets)
13
+ end
14
+
15
+ variable_name
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def process_short_syntax(secret_name, global_secrets_data)
22
+ global_secret = find_global_secret!(secret_name, global_secrets_data)
23
+
24
+ global_secret[:secret_variable]
25
+ end
26
+
27
+ def find_global_secret!(secret_name, global_secrets_data)
28
+ detected_secret = global_secrets_data.detect { |global_secret_data| global_secret_data[:secret_name] == secret_name }
29
+ error_message = I18n.t('compose.global_secret_not_found', secret: secret_name)
30
+ raise UffizziCore::ComposeFile::ParseError, error_message if detected_secret.nil?
31
+
32
+ detected_secret
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ServicesOptionsService
4
+ class << self
5
+ def parse(services, global_configs_data, global_secrets_data, compose_payload)
6
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.no_services') if services.nil? || services.keys.empty?
7
+
8
+ services.keys.map do |service|
9
+ service_data = prepare_service_data(service, services.fetch(service), global_configs_data, global_secrets_data, compose_payload)
10
+
11
+ if service_data[:image].blank? && service_data[:build].blank?
12
+ raise UffizziCore::ComposeFile::ParseError, I18n.t('compose.image_build_no_specified', value: service)
13
+ end
14
+
15
+ service_data
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def prepare_service_data(service_name, service_data, global_configs_data, global_secrets_data, compose_payload)
22
+ options_data = {}
23
+ service_data.each_pair do |key, value|
24
+ service_key = key.to_sym
25
+
26
+ options_data[service_key] = case service_key
27
+ when :image
28
+ UffizziCore::ComposeFile::ServicesOptions::ImageService.parse(value)
29
+ when :build
30
+ UffizziCore::ComposeFile::ServicesOptions::BuildService.parse(value, compose_payload)
31
+ when :env_file
32
+ UffizziCore::ComposeFile::ServicesOptions::EnvFileService.parse(value)
33
+ when :environment
34
+ UffizziCore::ComposeFile::ServicesOptions::EnvironmentService.parse(value)
35
+ when :configs
36
+ UffizziCore::ComposeFile::ServicesOptions::ConfigsService.parse(value, global_configs_data)
37
+ when :secrets
38
+ UffizziCore::ComposeFile::ServicesOptions::SecretsService.parse(value, global_secrets_data)
39
+ when :deploy
40
+ UffizziCore::ComposeFile::ServicesOptions::DeployService.parse(value)
41
+ when :entrypoint
42
+ UffizziCore::ComposeFile::ServicesOptions::EntrypointService.parse(value)
43
+ when :command
44
+ UffizziCore::ComposeFile::ServicesOptions::CommandService.parse(value)
45
+ when :'x-uffizzi-continuous-preview', :'x-uffizzi-continuous-previews'
46
+ UffizziCore::ComposeFile::ContinuousPreviewOptionsService.parse(value)
47
+ end
48
+ end
49
+
50
+ options_data[:container_name] = service_name
51
+
52
+ options_data
53
+ end
54
+ end
55
+ end