From bad7ee09845eb24144081c5305f26c63804fd11f Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Thu, 9 Feb 2023 15:29:23 -0600 Subject: [PATCH 01/19] Adding Google Play Integration --- .../javascripts/integrations/constants.js | 2 + .../components/integration_forms/section.vue | 4 + .../edit/components/sections/google_play.vue | 99 +++++++++++++ .../edit/components/upload_dropzone.vue | 130 ++++++++++++++++++ .../concerns/integrations/params.rb | 2 + app/models/integration.rb | 2 +- app/models/integrations/google_play.rb | 90 ++++++++++++ app/models/project.rb | 1 + .../development/google_play_integration.yml | 8 ++ lib/api/helpers/integrations_helpers.rb | 14 ++ 10 files changed, 351 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/integrations/edit/components/sections/google_play.vue create mode 100644 app/assets/javascripts/integrations/edit/components/upload_dropzone.vue create mode 100644 app/models/integrations/google_play.rb create mode 100644 config/feature_flags/development/google_play_integration.yml diff --git a/app/assets/javascripts/integrations/constants.js b/app/assets/javascripts/integrations/constants.js index e9bcc789bcb228..6b5a828c00901a 100644 --- a/app/assets/javascripts/integrations/constants.js +++ b/app/assets/javascripts/integrations/constants.js @@ -33,6 +33,7 @@ export const integrationFormSections = { JIRA_ISSUES: 'jira_issues', TRIGGER: 'trigger', APPLE_APP_STORE: 'apple_app_store', + GOOGLE_PLAY: 'google_play', }; export const integrationFormSectionComponents = { @@ -42,6 +43,7 @@ export const integrationFormSectionComponents = { [integrationFormSections.JIRA_ISSUES]: 'IntegrationSectionJiraIssues', [integrationFormSections.TRIGGER]: 'IntegrationSectionTrigger', [integrationFormSections.APPLE_APP_STORE]: 'IntegrationSectionAppleAppStore', + [integrationFormSections.GOOGLE_PLAY]: 'IntegrationSectionGooglePlay', }; export const integrationTriggerEvents = { diff --git a/app/assets/javascripts/integrations/edit/components/integration_forms/section.vue b/app/assets/javascripts/integrations/edit/components/integration_forms/section.vue index d33f0ba317110d..5335b7b6ee2c49 100644 --- a/app/assets/javascripts/integrations/edit/components/integration_forms/section.vue +++ b/app/assets/javascripts/integrations/edit/components/integration_forms/section.vue @@ -32,6 +32,10 @@ export default { import( /* webpackChunkName: 'IntegrationSectionAppleAppStore' */ '~/integrations/edit/components/sections/apple_app_store.vue' ), + IntegrationSectionGooglePlay: () => + import( + /* webpackChunkName: 'IntegrationSectionGooglePlay' */ '~/integrations/edit/components/sections/google_play.vue' + ), }, directives: { SafeHtml, diff --git a/app/assets/javascripts/integrations/edit/components/sections/google_play.vue b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue new file mode 100644 index 00000000000000..6a10e74e30b67e --- /dev/null +++ b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue @@ -0,0 +1,99 @@ + + + diff --git a/app/assets/javascripts/integrations/edit/components/upload_dropzone.vue b/app/assets/javascripts/integrations/edit/components/upload_dropzone.vue new file mode 100644 index 00000000000000..bee1db2cd8a643 --- /dev/null +++ b/app/assets/javascripts/integrations/edit/components/upload_dropzone.vue @@ -0,0 +1,130 @@ + + diff --git a/app/controllers/concerns/integrations/params.rb b/app/controllers/concerns/integrations/params.rb index b8b93814e2b697..a13d6d07ab7558 100644 --- a/app/controllers/concerns/integrations/params.rb +++ b/app/controllers/concerns/integrations/params.rb @@ -73,6 +73,8 @@ module Params :server, :server_host, :server_port, + :service_account_key, + :service_account_key_file, :sound, :subdomain, :teamcity_url, diff --git a/app/models/integration.rb b/app/models/integration.rb index 8bef8b08c196ac..6aa3ef526705a5 100644 --- a/app/models/integration.rb +++ b/app/models/integration.rb @@ -27,7 +27,7 @@ class Integration < ApplicationRecord # TODO Shimo is temporary disabled on group and instance-levels. # See: https://gitlab.com/gitlab-org/gitlab/-/issues/345677 PROJECT_SPECIFIC_INTEGRATION_NAMES = %w[ - apple_app_store jenkins shimo + apple_app_store google_play jenkins shimo ].freeze # Fake integrations to help with local development. diff --git a/app/models/integrations/google_play.rb b/app/models/integrations/google_play.rb new file mode 100644 index 00000000000000..f5f5a9802a3697 --- /dev/null +++ b/app/models/integrations/google_play.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true +module Integrations + class GooglePlay < Integration + SECTION_TYPE_INTEGRATION = 'google_play' + + with_options if: :activated? do + validates :service_account_key, presence: true + end + + field :service_account_key_file, + section: SECTION_TYPE_CONNECTION, + required: true, + title: -> { s_('GooglePlay|The Google Play Service Account JSON Key.') }, + is_secret: false + + field :service_account_key, api_only: true + + def title + 'Google Play' + end + + def description + s_('GooglePlay|Use GitLab to build and release an app in Google Play.') + end + + def help + variable_list = [ + 'SUPPLY_JSON_KEY_DATA' + ] + + # rubocop:disable Layout/LineLength + texts = [ + s_("Use the Google Play integration to easily connect to Google Play with Fastlane in CI/CD pipelines."), + s_("After the Google Play integration is activated, the following protected variables will be created for CI/CD use."), + variable_list.join('
'), + s_(format("To get started, see the integration documentation for instructions on how to generate a Google Play Service Account key, and how to use this integration.", url: "#")).html_safe + ] + # rubocop:enable Layout/LineLength + + texts.join('

'.html_safe) + end + + def self.to_param + 'google_play' + end + + def self.supported_events + [] + end + + def sections + [ + { + type: SECTION_TYPE_INTEGRATION, + title: s_('Integrations|Integration details'), + description: help + } + ] + end + + def test(*_args) + response = client.apps + if response.has_key?(:errors) + { success: false, message: response[:errors].first[:title] } + else + { success: true } + end + end + + def ci_variables + return [] unless activated? + + [ + { key: 'SUPPLY_JSON_KEY_DATA', value: service_account_key, masked: true, public: false } + ] + end + + # private + + # def client + # config = { + # issuer_id: app_store_issuer_id, + # key_id: app_store_key_id, + # private_key: app_store_private_key + # } + + # AppStoreConnect::Client.new(config) + # end + end +end diff --git a/app/models/project.rb b/app/models/project.rb index b1bb0ff2bbb7ec..b71ed8ccec508f 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1637,6 +1637,7 @@ def find_or_initialize_integrations def disabled_integrations disabled_integrations = [] disabled_integrations << 'apple_app_store' unless Feature.enabled?(:apple_app_store_integration, self) + disabled_integrations << 'google_play' unless Feature.enabled?(:google_play_integration, self) disabled_integrations end diff --git a/config/feature_flags/development/google_play_integration.yml b/config/feature_flags/development/google_play_integration.yml new file mode 100644 index 00000000000000..7d31084f0394f5 --- /dev/null +++ b/config/feature_flags/development/google_play_integration.yml @@ -0,0 +1,8 @@ +--- +name: google_play_integration +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110440 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/389611 +milestone: '15.9' +type: development +group: group::incubation +default_enabled: false diff --git a/lib/api/helpers/integrations_helpers.rb b/lib/api/helpers/integrations_helpers.rb index d13a78db01cd0c..acf8255b24677a 100644 --- a/lib/api/helpers/integrations_helpers.rb +++ b/lib/api/helpers/integrations_helpers.rb @@ -453,6 +453,20 @@ def self.integrations desc: 'The URL of the external wiki' } ], + 'google-play' => [ + { + required: true, + name: :service_account_key, + type: String, + desc: 'The Google Play Service Account Key' + }, + { + required: true, + name: :service_account_key_file, + type: String, + desc: 'The Google Play Service Account Key file name' + } + ], 'hangouts-chat' => [ { required: true, -- GitLab From 647c16768b9165d026877325159b79ff58d04e6d Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Fri, 10 Feb 2023 10:00:42 -0600 Subject: [PATCH 02/19] Updated form, added testing method --- .../edit/components/sections/google_play.vue | 54 +++++-------------- .../edit/components/upload_dropzone.vue | 18 +++++-- app/models/integrations/google_play.rb | 27 +++++----- 3 files changed, 41 insertions(+), 58 deletions(-) diff --git a/app/assets/javascripts/integrations/edit/components/sections/google_play.vue b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue index 6a10e74e30b67e..2a9777d1188074 100644 --- a/app/assets/javascripts/integrations/edit/components/sections/google_play.vue +++ b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue @@ -1,23 +1,15 @@ diff --git a/app/models/integrations/google_play.rb b/app/models/integrations/google_play.rb index f5f5a9802a3697..9e30824ee68d8d 100644 --- a/app/models/integrations/google_play.rb +++ b/app/models/integrations/google_play.rb @@ -59,12 +59,10 @@ def sections end def test(*_args) - response = client.apps - if response.has_key?(:errors) - { success: false, message: response[:errors].first[:title] } - else - { success: true } - end + client.fetch_access_token! + { success: true } + rescue Signet::AuthorizationError => error + { success: false, message: error } end def ci_variables @@ -75,16 +73,15 @@ def ci_variables ] end - # private + private - # def client - # config = { - # issuer_id: app_store_issuer_id, - # key_id: app_store_key_id, - # private_key: app_store_private_key - # } + def client + scopes = ['https://www.googleapis.com/auth/androidpublisher'] - # AppStoreConnect::Client.new(config) - # end + Google::Auth::ServiceAccountCredentials.make_creds( + json_key_io: StringIO.new(service_account_key), + scope: scopes + ) + end end end -- GitLab From 074ae1df57a91d9250bd3c9d42618f35374ef5f9 Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Fri, 10 Feb 2023 13:16:08 -0600 Subject: [PATCH 03/19] Updated integration configuration --- .../concerns/integrations/params.rb | 1 - app/models/integrations/google_play.rb | 1 - app/models/project.rb | 1 + ...projects_inheriting_google_play_active.yml | 23 ++++++++++++++ doc/api/graphql/reference/index.md | 1 + lib/api/helpers/integrations_helpers.rb | 7 +---- locale/gitlab.pot | 30 +++++++++++++++++++ 7 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml diff --git a/app/controllers/concerns/integrations/params.rb b/app/controllers/concerns/integrations/params.rb index a13d6d07ab7558..2387fafe9d40f5 100644 --- a/app/controllers/concerns/integrations/params.rb +++ b/app/controllers/concerns/integrations/params.rb @@ -74,7 +74,6 @@ module Params :server_host, :server_port, :service_account_key, - :service_account_key_file, :sound, :subdomain, :teamcity_url, diff --git a/app/models/integrations/google_play.rb b/app/models/integrations/google_play.rb index 9e30824ee68d8d..69fe1113070e27 100644 --- a/app/models/integrations/google_play.rb +++ b/app/models/integrations/google_play.rb @@ -10,7 +10,6 @@ class GooglePlay < Integration field :service_account_key_file, section: SECTION_TYPE_CONNECTION, required: true, - title: -> { s_('GooglePlay|The Google Play Service Account JSON Key.') }, is_secret: false field :service_account_key, api_only: true diff --git a/app/models/project.rb b/app/models/project.rb index b71ed8ccec508f..c152c83c6a7420 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -188,6 +188,7 @@ def self.integration_association_name(name) has_one :emails_on_push_integration, class_name: 'Integrations::EmailsOnPush' has_one :ewm_integration, class_name: 'Integrations::Ewm' has_one :external_wiki_integration, class_name: 'Integrations::ExternalWiki' + has_one :google_play_integration, class_name: 'Integrations::GooglePlay' has_one :hangouts_chat_integration, class_name: 'Integrations::HangoutsChat' has_one :harbor_integration, class_name: 'Integrations::Harbor' has_one :irker_integration, class_name: 'Integrations::Irker' diff --git a/config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml b/config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml new file mode 100644 index 00000000000000..83549897b284ba --- /dev/null +++ b/config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml @@ -0,0 +1,23 @@ +--- +key_path: counts.projects_inheriting_google_play_active +description: Count of active projects inheriting integrations for Google Play +product_section: dev +product_stage: manage +product_group: integrations +product_category: integrations +value_type: number +status: active +milestone: "15.9" +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111621 +time_frame: all +data_source: database +data_category: optional +instrumentation_class: +performance_indicator_type: [] +distribution: +- ce +- ee +tier: +- free +- premium +- ultimate diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index a4696acdfb33fd..5dd3886d5c52f7 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -23597,6 +23597,7 @@ State of a Sentry error. | `EXTERNAL_WIKI_SERVICE` | ExternalWikiService type. | | `GITHUB_SERVICE` | GithubService type. | | `GITLAB_SLACK_APPLICATION_SERVICE` | GitlabSlackApplicationService type (Gitlab.com only). | +| `GOOGLE_PLAY_SERVICE` | GooglePlayService type. | | `HANGOUTS_CHAT_SERVICE` | HangoutsChatService type. | | `HARBOR_SERVICE` | HarborService type. | | `IRKER_SERVICE` | IrkerService type. | diff --git a/lib/api/helpers/integrations_helpers.rb b/lib/api/helpers/integrations_helpers.rb index acf8255b24677a..5ca00ae8b59ebd 100644 --- a/lib/api/helpers/integrations_helpers.rb +++ b/lib/api/helpers/integrations_helpers.rb @@ -459,12 +459,6 @@ def self.integrations name: :service_account_key, type: String, desc: 'The Google Play Service Account Key' - }, - { - required: true, - name: :service_account_key_file, - type: String, - desc: 'The Google Play Service Account Key file name' } ], 'hangouts-chat' => [ @@ -938,6 +932,7 @@ def self.integration_classes ::Integrations::EmailsOnPush, ::Integrations::Ewm, ::Integrations::ExternalWiki, + ::Integrations::GooglePlay, ::Integrations::HangoutsChat, ::Integrations::Harbor, ::Integrations::Irker, diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 85484b1505e0e9..72782f240c8bfc 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3702,6 +3702,9 @@ msgstr "" msgid "After the Apple App Store Connect integration is activated, the following protected variables will be created for CI/CD use." msgstr "" +msgid "After the Google Play integration is activated, the following protected variables will be created for CI/CD use." +msgstr "" + msgid "After the export is complete, download the data file from a notification email or from this page. You can then import the data file from the %{strong_text_start}Create new group%{strong_text_end} page of another GitLab instance." msgstr "" @@ -19649,6 +19652,30 @@ msgstr "" msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts." msgstr "" +msgid "GooglePlay|Drag your Service Account Key file here or %{linkStart}click to upload%{linkEnd}." +msgstr "" + +msgid "GooglePlay|Drop your Service Account Key file to start the upload." +msgstr "" + +msgid "GooglePlay|Error: You are trying to upload something other than a Service Account Key file." +msgstr "" + +msgid "GooglePlay|Leave empty to use your current Service Account Key." +msgstr "" + +msgid "GooglePlay|The Google Play Service Account JSON Key." +msgstr "" + +msgid "GooglePlay|The Google Play Service Account Key (.json)" +msgstr "" + +msgid "GooglePlay|Upload a new Google Play Service Account Key (replace %{currentFileName})" +msgstr "" + +msgid "GooglePlay|Use GitLab to build and release an app in Google Play." +msgstr "" + msgid "Got it" msgstr "" @@ -46426,6 +46453,9 @@ msgstr "" msgid "Use the Apple App Store Connect integration to easily connect to the Apple App Store with Fastlane in CI/CD pipelines." msgstr "" +msgid "Use the Google Play integration to easily connect to Google Play with Fastlane in CI/CD pipelines." +msgstr "" + msgid "Use the link below to confirm your email address (%{email})" msgstr "" -- GitLab From 6ac9c93fdf6e531b03ef0409bd7764675a2f4f59 Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Fri, 10 Feb 2023 13:52:50 -0600 Subject: [PATCH 04/19] Linting and test fixes --- app/models/integrations/google_play.rb | 4 +++- ...0230210184724_projects_inheriting_google_play_active.yml | 1 - lib/api/helpers/integrations_helpers.rb | 6 ++++++ locale/gitlab.pot | 3 --- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/models/integrations/google_play.rb b/app/models/integrations/google_play.rb index 69fe1113070e27..f773e0716a4464 100644 --- a/app/models/integrations/google_play.rb +++ b/app/models/integrations/google_play.rb @@ -1,10 +1,12 @@ # frozen_string_literal: true + module Integrations class GooglePlay < Integration SECTION_TYPE_INTEGRATION = 'google_play' with_options if: :activated? do validates :service_account_key, presence: true + validates :service_account_key_file, presence: true end field :service_account_key_file, @@ -12,7 +14,7 @@ class GooglePlay < Integration required: true, is_secret: false - field :service_account_key, api_only: true + field :service_account_key, api_only: true, is_secret: false def title 'Google Play' diff --git a/config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml b/config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml index 83549897b284ba..9a9144d60ea41a 100644 --- a/config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml +++ b/config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml @@ -12,7 +12,6 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111621 time_frame: all data_source: database data_category: optional -instrumentation_class: performance_indicator_type: [] distribution: - ce diff --git a/lib/api/helpers/integrations_helpers.rb b/lib/api/helpers/integrations_helpers.rb index 5ca00ae8b59ebd..661583e0ef9497 100644 --- a/lib/api/helpers/integrations_helpers.rb +++ b/lib/api/helpers/integrations_helpers.rb @@ -459,6 +459,12 @@ def self.integrations name: :service_account_key, type: String, desc: 'The Google Play Service Account Key' + }, + { + required: true, + name: :service_account_key_file, + type: String, + desc: 'The Google Play Service Account Key File Name' } ], 'hangouts-chat' => [ diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 72782f240c8bfc..2005b201ba3749 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -19664,9 +19664,6 @@ msgstr "" msgid "GooglePlay|Leave empty to use your current Service Account Key." msgstr "" -msgid "GooglePlay|The Google Play Service Account JSON Key." -msgstr "" - msgid "GooglePlay|The Google Play Service Account Key (.json)" msgstr "" -- GitLab From 7ee77dcee095b442d43c17e2f58b88c9a78ee330 Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Wed, 22 Feb 2023 14:24:11 -0600 Subject: [PATCH 05/19] Adding tests, docs, and additional metrics definitions --- .../edit/components/sections/google_play.vue | 18 ++- .../edit/components/upload_dropzone.vue | 142 ------------------ app/models/integrations/google_play.rb | 6 +- ...0222192643_projects_google_play_active.yml | 22 +++ ...222193011_instances_google_play_active.yml | 22 +++ ...1_groups_inheriting_google_play_active.yml | 22 +++ ...230222193255_groups_google_play_active.yml | 22 +++ db/docs/integrations.yml | 1 + doc/user/project/integrations/google_play.md | 51 +++++++ .../projects/integrations/google_play_spec.rb | 25 +++ spec/fixtures/service_account.json | 12 ++ .../components/sections/google_play_spec.js | 57 +++++++ 12 files changed, 248 insertions(+), 152 deletions(-) delete mode 100644 app/assets/javascripts/integrations/edit/components/upload_dropzone.vue create mode 100644 config/metrics/counts_all/20230222192643_projects_google_play_active.yml create mode 100644 config/metrics/counts_all/20230222193011_instances_google_play_active.yml create mode 100644 config/metrics/counts_all/20230222193151_groups_inheriting_google_play_active.yml create mode 100644 config/metrics/counts_all/20230222193255_groups_google_play_active.yml create mode 100644 doc/user/project/integrations/google_play.md create mode 100644 spec/features/projects/integrations/google_play_spec.rb create mode 100644 spec/fixtures/service_account.json create mode 100644 spec/frontend/integrations/edit/components/sections/google_play_spec.js diff --git a/app/assets/javascripts/integrations/edit/components/sections/google_play.vue b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue index 2a9777d1188074..30737184bcc4e5 100644 --- a/app/assets/javascripts/integrations/edit/components/sections/google_play.vue +++ b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue @@ -1,14 +1,14 @@ - diff --git a/app/models/integrations/google_play.rb b/app/models/integrations/google_play.rb index f773e0716a4464..0aa942c236f1d8 100644 --- a/app/models/integrations/google_play.rb +++ b/app/models/integrations/google_play.rb @@ -2,14 +2,14 @@ module Integrations class GooglePlay < Integration - SECTION_TYPE_INTEGRATION = 'google_play' + SECTION_TYPE_GOOGLE_PLAY = 'google_play' with_options if: :activated? do validates :service_account_key, presence: true validates :service_account_key_file, presence: true end - field :service_account_key_file, + field :service_account_key_file_name, section: SECTION_TYPE_CONNECTION, required: true, is_secret: false @@ -52,7 +52,7 @@ def self.supported_events def sections [ { - type: SECTION_TYPE_INTEGRATION, + type: SECTION_TYPE_GOOGLE_PLAY, title: s_('Integrations|Integration details'), description: help } diff --git a/config/metrics/counts_all/20230222192643_projects_google_play_active.yml b/config/metrics/counts_all/20230222192643_projects_google_play_active.yml new file mode 100644 index 00000000000000..b2ba98825d3e6e --- /dev/null +++ b/config/metrics/counts_all/20230222192643_projects_google_play_active.yml @@ -0,0 +1,22 @@ +--- +key_path: counts.projects_google_play_active +description: Count of projects with active integrations for Google Play +product_section: dev +product_stage: manage +product_group: integrations +product_category: integrations +value_type: number +status: active +milestone: "15.10" +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111621 +time_frame: all +data_source: database +data_category: optional +performance_indicator_type: [] +distribution: +- ce +- ee +tier: +- free +- premium +- ultimate diff --git a/config/metrics/counts_all/20230222193011_instances_google_play_active.yml b/config/metrics/counts_all/20230222193011_instances_google_play_active.yml new file mode 100644 index 00000000000000..00f99ed13f4a42 --- /dev/null +++ b/config/metrics/counts_all/20230222193011_instances_google_play_active.yml @@ -0,0 +1,22 @@ +--- +key_path: counts.instances_google_play_active +description: Count of instances with active integrations for Google Play +product_section: dev +product_stage: manage +product_group: integrations +product_category: integrations +value_type: number +status: active +milestone: "15.10" +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111621 +time_frame: all +data_source: database +data_category: optional +performance_indicator_type: [] +distribution: +- ce +- ee +tier: +- free +- premium +- ultimate diff --git a/config/metrics/counts_all/20230222193151_groups_inheriting_google_play_active.yml b/config/metrics/counts_all/20230222193151_groups_inheriting_google_play_active.yml new file mode 100644 index 00000000000000..1dad27560b69ce --- /dev/null +++ b/config/metrics/counts_all/20230222193151_groups_inheriting_google_play_active.yml @@ -0,0 +1,22 @@ +--- +key_path: counts.groups_inheriting_google_play_active +description: Count of active groups inheriting integrations for Google Play +product_section: dev +product_stage: manage +product_group: integrations +product_category: integrations +value_type: number +status: active +milestone: "15.10" +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111621 +time_frame: all +data_source: database +data_category: optional +performance_indicator_type: [] +distribution: +- ce +- ee +tier: +- free +- premium +- ultimate diff --git a/config/metrics/counts_all/20230222193255_groups_google_play_active.yml b/config/metrics/counts_all/20230222193255_groups_google_play_active.yml new file mode 100644 index 00000000000000..fe83398f9ecb0d --- /dev/null +++ b/config/metrics/counts_all/20230222193255_groups_google_play_active.yml @@ -0,0 +1,22 @@ +--- +key_path: counts.groups_google_play_active +description: Count of active groups inheriting integrations for Google Play +product_section: dev +product_stage: manage +product_group: integrations +product_category: integrations +value_type: number +status: active +milestone: "15.10" +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111621 +time_frame: all +data_source: database +data_category: optional +performance_indicator_type: [] +distribution: +- ce +- ee +tier: +- free +- premium +- ultimate diff --git a/db/docs/integrations.yml b/db/docs/integrations.yml index 5bb4f448541751..c1b18b29804ea9 100644 --- a/db/docs/integrations.yml +++ b/db/docs/integrations.yml @@ -26,6 +26,7 @@ classes: - Integrations::ExternalWiki - Integrations::Github - Integrations::GitlabSlackApplication +- Integrations::GooglePlay - Integrations::HangoutsChat - Integrations::Harbor - Integrations::Irker diff --git a/doc/user/project/integrations/google_play.md b/doc/user/project/integrations/google_play.md new file mode 100644 index 00000000000000..ba30f1f744c195 --- /dev/null +++ b/doc/user/project/integrations/google_play.md @@ -0,0 +1,51 @@ +--- +stage: Manage +group: Integrations +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments +--- + +# Google Play **(FREE)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111621) in GitLab 15.10 [with a flag](../../../administration/feature_flags.md) named `google_play_integration`. Disabled by default. + +FLAG: +On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `google_play_integration`. On GitLab.com, this feature is not available. + +With the Google Play integration, you can configure your CI/CD pipelines to connect to the [Google Play Console](https://play.google.com/console) to build and release apps for Android devices. + +The integration is designed to be able to work out of the box with [fastlane](http://fastlane.tools/), but can be used with other build tools as well. + +## Prerequisites + +A [Google Play Console](https://play.google.com/console/u/0/signup) developer account is required to enable this integration. + +## Configure GitLab + +GitLab supports enabling the Google Play integration at the project level. Complete these steps in GitLab: + +1. In the Google Cloud console, generate a new service account key for your project by following [these instructions](https://developers.google.com/android-publisher/getting_started). +1. On the top bar, select **Main menu > Projects** and find your project. +1. On the left sidebar, select **Settings > Integrations**. +1. Select **Google Play**. +1. Turn on the **Active** toggle under **Enable Integration**. +1. Provide the The Google Play Service Account Key +1. Select **Save changes**. + +After the Google Play integration is activated: + +- The global variables `$SUPPLY_JSON_KEY_DATA` are created for CI/CD use. + +### CI/CD variable security + +Malicious code pushed to your `.gitlab-ci.yml` file could compromise your variables, including `$SUPPLY_JSON_KEY_DATA`, and send them to a third-party server. For more details, see [CI/CD variable security](../../../ci/variables/index.md#cicd-variable-security). + +## fastlane Example + +Because this integration works out of the box with fastlane adding the example code below to an app's `fastlane/Fastfile` activates the integration and will upload the build to the given track in Google Play. + +```ruby +upload_to_play_store( + track: 'internal', + aab: '../build/app/outputs/bundle/release/app-release.aab' +) +``` diff --git a/spec/features/projects/integrations/google_play_spec.rb b/spec/features/projects/integrations/google_play_spec.rb new file mode 100644 index 00000000000000..e8a970076ac1dd --- /dev/null +++ b/spec/features/projects/integrations/google_play_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Upload Dropzone Field', feature_category: :integrations do + include_context 'project integration activation' + + it 'uploads the file data to the correct form fields and updates the messaging correctly', :js, :aggregate_failures do + visit_project_integration('Google Play') + + expect(page).to have_content('Drag your Service Account Key file here or click to upload.') + expect(page).not_to have_content('service_account.json') + + find("input[name='service[dropzone_file_name]']", + visible: false).set(Rails.root.join('spec/fixtures/service_account.json')) + + expect(find("input[name='service[service_account_key]']", + visible: false).value).to eq(File.read(Rails.root.join('spec/fixtures/service_account.json'))) + expect(find("input[name='service[service_account_key_file_name]']", + visible: false).value).to eq('service_account.json') + + expect(page).not_to have_content('Drag your Service Account Key file here or click to upload.') + expect(page).to have_content('service_account.json') + end +end diff --git a/spec/fixtures/service_account.json b/spec/fixtures/service_account.json new file mode 100644 index 00000000000000..9f7f5526cf5264 --- /dev/null +++ b/spec/fixtures/service_account.json @@ -0,0 +1,12 @@ +{ + "type": "service_account", + "project_id": "demo-app-123", + "private_key_id": "47f0b1700983da548af6fcd37007f42996099999", + "private_key": "-----BEGIN PRIVATE KEY-----\nABCDEFIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJn8w20WcN+fi5\nIhO1BEFCv7ExK8J5rW5Pc8XpJgpQoL5cfv6qC6aS+x4maI7S4AG7diqXBLCfjlnA\nqBzXwCRnnPtQhu+v1ehAj5fGNa7F51f9aacRNmKdHzNmWZEPDuLqq0I/Ewcsotu+\nnb+tCYk1o2ahyPZau8JtXFZs7oZb7SrfgoSJemccxeVreGm1Dt6SM74/3qJAeHN/\niK/v0IiQP1GS4Jxgz38XQGo+jiTpNrFcf4S0RNxKcNf+tuuEBDi57LBLwdotM7E5\nF1l9pZZMWkmQKQIxeER6+2HuE56V6QPITwkQ/u9XZFQSgl4SBIw2sHr5D/xaUxjw\n+kMy2Jt9AgMBAAECggEACL7E34rRIWbP043cv3ZQs1RiWzY2mvWmCiMEzkz0rRRv\nyqNv0yXVYtzVV7KjdpY56leLgjM1Sv0PEQoUUtpWFJAXSXdKLaewSXPrpXCoz5OD\nekMgeItnQcE7nECdyAKsCSQw/SXg4t4p0a3WGsCwt3If2TwWIrov9R4zGcn1wMZn\n922WtZDmh2NqdTZIKElWZLxNlIr/1v88mAp7oSa1DLfqWkwEEnxK7GGAiwN8ARIF\nkvgiuKdsHBf5aNKg70xN6AcZx/Z4+KZxXxyKKF5VkjCtDzA97EjJqftDPwGTkela\n2bgiDSJs0Un0wQpFFRDrlfyo7rr9Ey/Gf4rR66NWeQKBgQD7qPP55xoWHCDvoK9P\nMN67qFLNDPWcKVKr8siwUlZ6/+acATXjfNUjsJLM7vBxYLjdtFxQ/vojJTQyMxHt\n80wARDk1DTu2zhltL2rKo6LfbwjQsot1MLZFXAMwqtHTLfURaj8kO1JDV/j+4a94\nP0gzNMiBYAKWm6z08akEz2TrhQKBgQDNGfFvtxo4Mf6AA3iYXCwc0CJXb+cqZkW/\n7glnV+vDqYVo23HJaKHFD+Xqaj+cUrOUNglWgT9WSCZR++Hzw1OCPZvX2V9Z6eQh\ngqOBX6D19q9jfShfxLywEAD5pk7LMINumsNm6H+6shJQK5c67bsM9/KQbSnIlWhw\n7JBe8OlFmQKBgQDREyF2mb/7ZG0ch8N9qB0zjHkV79FRZqdPQUnn6s/8KgO90eei\nUkCFARpE9bF+kBul3UTg6aSIdE0z82fO51VZ11Qrtg3JJtrK8hznsyEKPaX2NI9V\n0h1r7DCeSxw9NS4nxLwmbr4+QqUTpA3yeaiTGiQGD+y2kSkU6nxACclPPQKBgFkb\nkVqg6YJKrjB90ZIYUY3/GzxzwLIaFumpCGretu6eIvkIhiokDExqeNBccuB+ych1\npZ7wrkzVMdjinythzFFEZQXlSdjtlhC9Cj52Bp92GoMV6EmbVwMDIPlVuNvsat3N\n3WFDV+ML5IryNVUD3gVnX/pBgyrDRsnw7VRiRGbZAoGBANxZwGKZo0zpyb5O5hS6\nxVrgJtIySlV5BOEjFXKeLwzByht8HmrHhSWix6WpPejfK1RHhl3boU6t9yeC0cre\nvUI/Y9LBhHXjSwWCWlqVe9yYqsde+xf0UYRS8IoaoJjus7YVJr9yPpCboEF28ZmQ\ndVBlpZYg6oLIar6waaLMz/1B\n-----END PRIVATE KEY-----\n", + "client_email": "demo-app-account@demo-app-374914.iam.gserviceaccount.com", + "client_id": "111111116847110173051", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/demo-app-account%40demo-app-374914.iam.gserviceaccount.com" +} diff --git a/spec/frontend/integrations/edit/components/sections/google_play_spec.js b/spec/frontend/integrations/edit/components/sections/google_play_spec.js new file mode 100644 index 00000000000000..872c014b9766f8 --- /dev/null +++ b/spec/frontend/integrations/edit/components/sections/google_play_spec.js @@ -0,0 +1,57 @@ +import { shallowMount } from '@vue/test-utils'; + +import IntegrationSectionGooglePlay from '~/integrations/edit/components/sections/google_play.vue'; +import UploadDropzoneField from '~/integrations/edit/components/upload_dropzone_field.vue'; +import { createStore } from '~/integrations/edit/store'; + +describe('IntegrationSectionGooglePlay', () => { + let wrapper; + + const createComponent = (componentFields) => { + const store = createStore({ + customState: { ...componentFields }, + }); + wrapper = shallowMount(IntegrationSectionGooglePlay, { + store, + }); + }; + + const componentFields = (fileName = '') => { + return { + fields: [ + { + name: 'service_account_key_file_name', + value: fileName, + }, + ], + }; + }; + + const findUploadDropzoneField = () => wrapper.findComponent(UploadDropzoneField); + + describe('computed properties', () => { + it('renders UploadDropzoneField with default values', () => { + createComponent(componentFields()); + + const field = findUploadDropzoneField(); + + expect(field.exists()).toBe(true); + expect(field.props()).toMatchObject({ + label: 'The Google Play Service Account Key (.json)', + helpText: '', + }); + }); + + it('renders UploadDropzoneField with custom values for an attached file', () => { + createComponent(componentFields('fileName.txt')); + + const field = findUploadDropzoneField(); + + expect(field.exists()).toBe(true); + expect(field.props()).toMatchObject({ + label: 'Upload a new Google Play Service Account Key (replace fileName.txt)', + helpText: 'Leave empty to use your current Service Account Key.', + }); + }); + }); +}); -- GitLab From 8732452c122acb462567ca80000c68a4833eff4a Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Wed, 22 Feb 2023 15:29:50 -0600 Subject: [PATCH 06/19] Adding additional tests & pipeline integrations --- app/models/ci/build.rb | 9 +++ app/models/integrations/google_play.rb | 2 +- lib/api/helpers/integrations_helpers.rb | 2 +- spec/factories/integrations.rb | 9 +++ spec/lib/gitlab/import_export/all_models.yml | 1 + spec/models/ci/build_spec.rb | 40 ++++++++++ spec/models/integrations/google_play_spec.rb | 84 ++++++++++++++++++++ spec/models/project_spec.rb | 1 + 8 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 spec/models/integrations/google_play_spec.rb diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 0941f6d4cf0c82..0c2332d801208c 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -71,6 +71,7 @@ class Build < Ci::Processable delegate :gitlab_deploy_token, to: :project delegate :harbor_integration, to: :project delegate :apple_app_store_integration, to: :project + delegate :google_play_integration, to: :project delegate :trigger_short_token, to: :trigger_request, allow_nil: true delegate :ensure_persistent_ref, to: :pipeline delegate :enable_debug_trace!, to: :metadata @@ -599,6 +600,7 @@ def persisted_variables .concat(deploy_token_variables) .concat(harbor_variables) .concat(apple_app_store_variables) + .concat(google_play_variables) end end @@ -649,6 +651,13 @@ def apple_app_store_variables Gitlab::Ci::Variables::Collection.new(apple_app_store_integration.ci_variables) end + def google_play_variables + return [] unless google_play_integration.try(:activated?) + return [] unless pipeline.protected_ref? + + Gitlab::Ci::Variables::Collection.new(google_play_integration.ci_variables) + end + def features { trace_sections: true, diff --git a/app/models/integrations/google_play.rb b/app/models/integrations/google_play.rb index 0aa942c236f1d8..2d3f4484c7d0e3 100644 --- a/app/models/integrations/google_play.rb +++ b/app/models/integrations/google_play.rb @@ -6,7 +6,7 @@ class GooglePlay < Integration with_options if: :activated? do validates :service_account_key, presence: true - validates :service_account_key_file, presence: true + validates :service_account_key_file_name, presence: true end field :service_account_key_file_name, diff --git a/lib/api/helpers/integrations_helpers.rb b/lib/api/helpers/integrations_helpers.rb index 661583e0ef9497..60cb61ef02f744 100644 --- a/lib/api/helpers/integrations_helpers.rb +++ b/lib/api/helpers/integrations_helpers.rb @@ -462,7 +462,7 @@ def self.integrations }, { required: true, - name: :service_account_key_file, + name: :service_account_key_file_name, type: String, desc: 'The Google Play Service Account Key File Name' } diff --git a/spec/factories/integrations.rb b/spec/factories/integrations.rb index dccca9ce30decf..5a666e57ad1860 100644 --- a/spec/factories/integrations.rb +++ b/spec/factories/integrations.rb @@ -265,6 +265,15 @@ app_store_private_key { File.read('spec/fixtures/auth_key.p8') } end + factory :google_play_integration, class: 'Integrations::GooglePlay' do + project + active { true } + type { 'Integrations::GooglePlay' } + + service_account_key_file_name { 'service_account.json' } + service_account_key { File.read('spec/fixtures/service_account.json') } + end + # this is for testing storing values inside properties, which is deprecated and will be removed in # https://gitlab.com/gitlab-org/gitlab/issues/29404 trait :without_properties_callback do diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 056dc1f1966386..490be954792eff 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -532,6 +532,7 @@ project: - discord_integration - drone_ci_integration - emails_on_push_integration +- google_play_integration - pipelines_email_integration - mattermost_slash_commands_integration - shimo_integration diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 492768df14e96a..54e23057923624 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -3639,6 +3639,46 @@ end end + context 'for the google_play integration' do + let_it_be(:google_play_integration) { create(:google_play_integration) } + + let(:google_play_variables) do + [ + { key: 'SUPPLY_JSON_KEY_DATA', value: google_play_integration.service_account_key, masked: true, public: false } + ] + end + + context 'when the google_play integration exists' do + context 'when a build is protected' do + before do + allow(build.pipeline).to receive(:protected_ref?).and_return(true) + build.project.update!(google_play_integration: google_play_integration) + end + + it 'includes google_play variables' do + is_expected.to include(*google_play_variables) + end + end + + context 'when a build is not protected' do + before do + allow(build.pipeline).to receive(:protected_ref?).and_return(false) + build.project.update!(google_play_integration: google_play_integration) + end + + it 'does not include the googe_play variable' do + expect(subject.find { |v| v[:key] == 'SUPPLY_JSON_KEY_DATA' }).to be_nil + end + end + end + + context 'when the googel_play integration does not exist' do + it 'does not include googel_play variable' do + expect(subject.find { |v| v[:key] == 'SUPPLY_JSON_KEY_DATA' }).to be_nil + end + end + end + context 'when build has dependency which has dotenv variable' do let!(:prepare) { create(:ci_build, pipeline: pipeline, stage_idx: 0) } let!(:build) { create(:ci_build, pipeline: pipeline, stage_idx: 1, options: { dependencies: [prepare.name] }) } diff --git a/spec/models/integrations/google_play_spec.rb b/spec/models/integrations/google_play_spec.rb new file mode 100644 index 00000000000000..4bd62280ed4595 --- /dev/null +++ b/spec/models/integrations/google_play_spec.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Integrations::GooglePlay, feature_category: :mobile_devops do + describe 'Validations' do + context 'when active' do + before do + subject.active = true + end + + it { is_expected.to validate_presence_of :service_account_key } + it { is_expected.to validate_presence_of :service_account_key_file_name } + end + end + + context 'when integration is enabled' do + let(:google_play_integration) { build(:google_play_integration) } + + describe '#fields' do + it 'returns custom fields' do + expect(google_play_integration.fields.pluck(:name)).to match_array(%w[service_account_key + service_account_key_file_name]) + end + end + + describe '#test' do + it 'returns true for a successful request' do + allow(Google::Auth::ServiceAccountCredentials).to receive_message_chain(:make_creds, :fetch_access_token!) + expect(google_play_integration.test[:success]).to be true + end + + it 'returns false for an invalid request' do + allow(Google::Auth::ServiceAccountCredentials).to receive_message_chain(:make_creds, + :fetch_access_token!).and_raise(Signet::AuthorizationError.new('error')) + expect(google_play_integration.test[:success]).to be false + end + end + + describe '#help' do + it 'renders prompt information' do + expect(google_play_integration.help).not_to be_empty + end + end + + describe '.to_param' do + it 'returns the name of the integration' do + expect(described_class.to_param).to eq('google_play') + end + end + + describe '#ci_variables' do + let(:google_play_integration) { build_stubbed(:google_play_integration) } + + it 'returns vars when the integration is activated' do + ci_vars = [ + { + key: 'SUPPLY_JSON_KEY_DATA', + value: google_play_integration.service_account_key, + masked: true, + public: false + } + ] + + expect(google_play_integration.ci_variables).to match_array(ci_vars) + end + + it 'returns an empty array when the integration is disabled' do + google_play_integration = build_stubbed(:google_play_integration, active: false) + expect(google_play_integration.ci_variables).to match_array([]) + end + end + end + + context 'when integration is disabled' do + let(:google_play_integration) { build_stubbed(:google_play_integration, active: false) } + + describe '#ci_variables' do + it 'returns an empty array' do + expect(google_play_integration.ci_variables).to match_array([]) + end + end + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 9db1dde6294682..346948bb0263ea 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -50,6 +50,7 @@ it { is_expected.to have_one(:packagist_integration) } it { is_expected.to have_one(:pushover_integration) } it { is_expected.to have_one(:apple_app_store_integration) } + it { is_expected.to have_one(:google_play_integration) } it { is_expected.to have_one(:asana_integration) } it { is_expected.to have_many(:boards) } it { is_expected.to have_one(:campfire_integration) } -- GitLab From 3deb38dbca968bfb917088d650bce1ff61203225 Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Wed, 22 Feb 2023 17:11:54 -0600 Subject: [PATCH 07/19] fixes metrics linting failure --- .../counts_all/20230222192643_projects_google_play_active.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/metrics/counts_all/20230222192643_projects_google_play_active.yml b/config/metrics/counts_all/20230222192643_projects_google_play_active.yml index b2ba98825d3e6e..712a9b9cac1540 100644 --- a/config/metrics/counts_all/20230222192643_projects_google_play_active.yml +++ b/config/metrics/counts_all/20230222192643_projects_google_play_active.yml @@ -1,6 +1,6 @@ --- key_path: counts.projects_google_play_active -description: Count of projects with active integrations for Google Play +description: Count of projects with active integrations for Google Play product_section: dev product_stage: manage product_group: integrations -- GitLab From 835843a2f79b0b3c59928ca60146d7f0ea02e34d Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Thu, 23 Feb 2023 07:47:45 -0600 Subject: [PATCH 08/19] Updated milestone --- config/feature_flags/development/google_play_integration.yml | 2 +- .../20230210184724_projects_inheriting_google_play_active.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/feature_flags/development/google_play_integration.yml b/config/feature_flags/development/google_play_integration.yml index 7d31084f0394f5..81c509cdab7583 100644 --- a/config/feature_flags/development/google_play_integration.yml +++ b/config/feature_flags/development/google_play_integration.yml @@ -2,7 +2,7 @@ name: google_play_integration introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110440 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/389611 -milestone: '15.9' +milestone: '15.10' type: development group: group::incubation default_enabled: false diff --git a/config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml b/config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml index 9a9144d60ea41a..9a24543390a6be 100644 --- a/config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml +++ b/config/metrics/counts_all/20230210184724_projects_inheriting_google_play_active.yml @@ -7,7 +7,7 @@ product_group: integrations product_category: integrations value_type: number status: active -milestone: "15.9" +milestone: "15.10" introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111621 time_frame: all data_source: database -- GitLab From 0f0e9f02269a2051fb0876cfd02fa04448b2faeb Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Thu, 23 Feb 2023 13:45:34 -0600 Subject: [PATCH 09/19] Adding json schema validation --- .../edit/components/sections/google_play.vue | 4 +- .../concerns/integrations/params.rb | 1 + app/models/integrations/google_play.rb | 11 ++++- .../google_service_account_key.json | 48 +++++++++++++++++++ spec/models/ci/build_spec.rb | 4 +- spec/models/integrations/google_play_spec.rb | 21 +++++--- 6 files changed, 77 insertions(+), 12 deletions(-) create mode 100644 app/validators/json_schemas/google_service_account_key.json diff --git a/app/assets/javascripts/integrations/edit/components/sections/google_play.vue b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue index 30737184bcc4e5..80165b13a07b1c 100644 --- a/app/assets/javascripts/integrations/edit/components/sections/google_play.vue +++ b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue @@ -5,14 +5,14 @@ import UploadDropzoneField from '../upload_dropzone_field.vue'; import Connection from './connection.vue'; export default { - name: 'IntegrationSectionAppleAppStore', + name: 'IntegrationSectionGooglePlay', components: { Connection, UploadDropzoneField, }, data() { return { - dropzoneAllowList: ['.p12', '.json'], + dropzoneAllowList: ['.json'], }; }, i18n: { diff --git a/app/controllers/concerns/integrations/params.rb b/app/controllers/concerns/integrations/params.rb index 2387fafe9d40f5..7e1ba49d442d07 100644 --- a/app/controllers/concerns/integrations/params.rb +++ b/app/controllers/concerns/integrations/params.rb @@ -74,6 +74,7 @@ module Params :server_host, :server_port, :service_account_key, + :service_account_key_file_name, :sound, :subdomain, :teamcity_url, diff --git a/app/models/integrations/google_play.rb b/app/models/integrations/google_play.rb index 2d3f4484c7d0e3..fa3172dfa4a461 100644 --- a/app/models/integrations/google_play.rb +++ b/app/models/integrations/google_play.rb @@ -4,8 +4,11 @@ module Integrations class GooglePlay < Integration SECTION_TYPE_GOOGLE_PLAY = 'google_play' + KEY_SCHEMA_PATH = 'app/validators/json_schemas/google_service_account_key.json' + KEY_SCHEMA = JSONSchemer.schema(Rails.root.join(KEY_SCHEMA_PATH)) + with_options if: :activated? do - validates :service_account_key, presence: true + validate :service_account_key, :valid_service_account_key? validates :service_account_key_file_name, presence: true end @@ -84,5 +87,11 @@ def client scope: scopes ) end + + def valid_service_account_key? + return if KEY_SCHEMA.valid?(Gitlab::Json.parse(service_account_key)) + + errors.add(:service_account_key, "is not valid") + end end end diff --git a/app/validators/json_schemas/google_service_account_key.json b/app/validators/json_schemas/google_service_account_key.json new file mode 100644 index 00000000000000..d040ef19f66f6a --- /dev/null +++ b/app/validators/json_schemas/google_service_account_key.json @@ -0,0 +1,48 @@ +{ + "description": "Google service account key", + "type": "object", + "required": [ + "type", + "project_id", + "private_key_id", + "private_key", + "client_email", + "client_id", + "auth_uri", + "token_uri", + "auth_provider_x509_cert_url", + "client_x509_cert_url" + ], + "properties": { + "type": { + "const": "service_account" + }, + "project_id": { + "type": "string" + }, + "private_key_id": { + "type": "string" + }, + "private_key": { + "type": "string" + }, + "client_email": { + "type": "string" + }, + "client_id": { + "type": "string" + }, + "auth_uri": { + "type": "string" + }, + "token_uri": { + "type": "string" + }, + "auth_provider_x509_cert_url": { + "type": "string" + }, + "client_x509_cert_url": { + "type": "string" + } + } +} diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 54e23057923624..86d02c0acb78d3 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -3667,14 +3667,14 @@ end it 'does not include the googe_play variable' do - expect(subject.find { |v| v[:key] == 'SUPPLY_JSON_KEY_DATA' }).to be_nil + expect(subject[:key] == 'SUPPLY_JSON_KEY_DATA').to eq(false) end end end context 'when the googel_play integration does not exist' do it 'does not include googel_play variable' do - expect(subject.find { |v| v[:key] == 'SUPPLY_JSON_KEY_DATA' }).to be_nil + expect(subject[:key] == 'SUPPLY_JSON_KEY_DATA').to eq(false) end end end diff --git a/spec/models/integrations/google_play_spec.rb b/spec/models/integrations/google_play_spec.rb index 4bd62280ed4595..254fde9d46e9a8 100644 --- a/spec/models/integrations/google_play_spec.rb +++ b/spec/models/integrations/google_play_spec.rb @@ -3,14 +3,21 @@ require 'spec_helper' RSpec.describe Integrations::GooglePlay, feature_category: :mobile_devops do - describe 'Validations' do - context 'when active' do - before do - subject.active = true - end + context 'when validating the settings' do + let(:google_play_integration) { create(:google_play_integration) } + + it 'is valid when all the required values are provided' do + expect(google_play_integration.valid?).to be true + end + + it 'is invalid when the service account key does not match the expected format' do + google_play_integration.service_account_key = File.read('spec/fixtures/group.json') + expect(google_play_integration.valid?).to be false + end - it { is_expected.to validate_presence_of :service_account_key } - it { is_expected.to validate_presence_of :service_account_key_file_name } + it 'is invalid when the service_account_key_file_name is nil' do + google_play_integration.service_account_key_file_name = nil + expect(google_play_integration.valid?).to be false end end -- GitLab From 9ff71e8e36213143c2e129d3091a5545ecdbcdda Mon Sep 17 00:00:00 2001 From: Ashraf Khamis Date: Thu, 23 Feb 2023 20:04:17 +0000 Subject: [PATCH 10/19] Applying suggestions to integration docs --- doc/user/project/integrations/google_play.md | 26 +++++++++----------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/doc/user/project/integrations/google_play.md b/doc/user/project/integrations/google_play.md index ba30f1f744c195..83c4cd82363f70 100644 --- a/doc/user/project/integrations/google_play.md +++ b/doc/user/project/integrations/google_play.md @@ -13,35 +13,33 @@ On self-managed GitLab, by default this feature is not available. To make it ava With the Google Play integration, you can configure your CI/CD pipelines to connect to the [Google Play Console](https://play.google.com/console) to build and release apps for Android devices. -The integration is designed to be able to work out of the box with [fastlane](http://fastlane.tools/), but can be used with other build tools as well. +The Google Play integration works out of the box with [fastlane](https://fastlane.tools/). You can also use this integration with other build tools. -## Prerequisites +## Enable the integration in GitLab -A [Google Play Console](https://play.google.com/console/u/0/signup) developer account is required to enable this integration. +Prerequisites: -## Configure GitLab +- You must have a [Google Play Console](https://play.google.com/console/signup) developer account. +- You must [generate a new service account key for your project](https://developers.google.com/android-publisher/getting_started) from the Google Cloud console. -GitLab supports enabling the Google Play integration at the project level. Complete these steps in GitLab: +To enable the Google Play integration in GitLab: -1. In the Google Cloud console, generate a new service account key for your project by following [these instructions](https://developers.google.com/android-publisher/getting_started). 1. On the top bar, select **Main menu > Projects** and find your project. 1. On the left sidebar, select **Settings > Integrations**. 1. Select **Google Play**. -1. Turn on the **Active** toggle under **Enable Integration**. -1. Provide the The Google Play Service Account Key +1. In **Enable Integration**, select the **Active** checkbox. +1. In **Service account key**, drag or upload your key file. 1. Select **Save changes**. -After the Google Play integration is activated: - -- The global variables `$SUPPLY_JSON_KEY_DATA` are created for CI/CD use. +After you enable the integration, the global variables `$SUPPLY_JSON_KEY_DATA` are created for CI/CD use. ### CI/CD variable security -Malicious code pushed to your `.gitlab-ci.yml` file could compromise your variables, including `$SUPPLY_JSON_KEY_DATA`, and send them to a third-party server. For more details, see [CI/CD variable security](../../../ci/variables/index.md#cicd-variable-security). +Malicious code pushed to your `.gitlab-ci.yml` file could compromise your variables, including `$SUPPLY_JSON_KEY_DATA`, and send them to a third-party server. For more information, see [CI/CD variable security](../../../ci/variables/index.md#cicd-variable-security). -## fastlane Example +## Enable the integration in fastlane -Because this integration works out of the box with fastlane adding the example code below to an app's `fastlane/Fastfile` activates the integration and will upload the build to the given track in Google Play. +To enable the integration in fastlane and upload the build to the given track in Google Play, you can add the following code to your app's `fastlane/Fastfile`: ```ruby upload_to_play_store( -- GitLab From 075f0f9f624e0122af7d63179ae63c90bb89deb8 Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Thu, 23 Feb 2023 14:02:20 -0600 Subject: [PATCH 11/19] Updated messaging in UI --- .../edit/components/sections/google_play.vue | 12 +++++------- locale/gitlab.pot | 10 +++++----- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/integrations/edit/components/sections/google_play.vue b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue index 80165b13a07b1c..fa814d59e38a9f 100644 --- a/app/assets/javascripts/integrations/edit/components/sections/google_play.vue +++ b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue @@ -17,20 +17,18 @@ export default { }, i18n: { dropzoneDescription: s__( - 'GooglePlay|Drag your Service Account Key file here or %{linkStart}click to upload%{linkEnd}.', + 'GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}.', ), dropzoneErrorMessage: s__( 'GooglePlay|Error: You are trying to upload something other than a Service Account Key file.', ), - dropzoneConfirmMessage: s__( - 'GooglePlay|Drop your Service Account Key file to start the upload.', - ), - dropzoneEmptyInputName: s__('GooglePlay|The Google Play Service Account Key (.json)'), + dropzoneConfirmMessage: s__('GooglePlay|Drop your key file to start the upload.'), + dropzoneEmptyInputName: s__('GooglePlay|Service account key (.json)'), dropzoneNonEmptyInputName: s__( - 'GooglePlay|Upload a new Google Play Service Account Key (replace %{currentFileName})', + 'GooglePlay|Upload a new service account key (replace %{currentFileName})', ), dropzoneNoneEmpyInputHelp: s__( - 'GooglePlay|Leave empty to use your current Service Account Key.', + 'GooglePlay|Leave empty to use your current service account key.', ), }, computed: { diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 2005b201ba3749..97afbbcd189482 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -19652,22 +19652,22 @@ msgstr "" msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts." msgstr "" -msgid "GooglePlay|Drag your Service Account Key file here or %{linkStart}click to upload%{linkEnd}." +msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}." msgstr "" -msgid "GooglePlay|Drop your Service Account Key file to start the upload." +msgid "GooglePlay|Drop your key file to start the upload." msgstr "" msgid "GooglePlay|Error: You are trying to upload something other than a Service Account Key file." msgstr "" -msgid "GooglePlay|Leave empty to use your current Service Account Key." +msgid "GooglePlay|Leave empty to use your current service account key." msgstr "" -msgid "GooglePlay|The Google Play Service Account Key (.json)" +msgid "GooglePlay|Service account key (.json)" msgstr "" -msgid "GooglePlay|Upload a new Google Play Service Account Key (replace %{currentFileName})" +msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})" msgstr "" msgid "GooglePlay|Use GitLab to build and release an app in Google Play." -- GitLab From 1ee6ba47f86122ca56b34d09b2a9d3e382ba83ba Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Thu, 23 Feb 2023 18:11:30 -0600 Subject: [PATCH 12/19] fixing tests --- .../edit/components/sections/google_play_spec.js | 6 +++--- .../features/integrations/integrations_shared_context.rb | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/spec/frontend/integrations/edit/components/sections/google_play_spec.js b/spec/frontend/integrations/edit/components/sections/google_play_spec.js index 872c014b9766f8..e9b9340d63c285 100644 --- a/spec/frontend/integrations/edit/components/sections/google_play_spec.js +++ b/spec/frontend/integrations/edit/components/sections/google_play_spec.js @@ -37,7 +37,7 @@ describe('IntegrationSectionGooglePlay', () => { expect(field.exists()).toBe(true); expect(field.props()).toMatchObject({ - label: 'The Google Play Service Account Key (.json)', + label: 'Service account key (.json)', helpText: '', }); }); @@ -49,8 +49,8 @@ describe('IntegrationSectionGooglePlay', () => { expect(field.exists()).toBe(true); expect(field.props()).toMatchObject({ - label: 'Upload a new Google Play Service Account Key (replace fileName.txt)', - helpText: 'Leave empty to use your current Service Account Key.', + label: 'Upload a new service account key (replace fileName.txt)', + helpText: 'Leave empty to use your current service account key.', }); }); }); diff --git a/spec/support/shared_contexts/features/integrations/integrations_shared_context.rb b/spec/support/shared_contexts/features/integrations/integrations_shared_context.rb index 178dad627eda6a..f07e4f6c9c37a5 100644 --- a/spec/support/shared_contexts/features/integrations/integrations_shared_context.rb +++ b/spec/support/shared_contexts/features/integrations/integrations_shared_context.rb @@ -76,6 +76,10 @@ hash.merge!(k => 'ABC1') elsif integration == 'apple_app_store' && k == :app_store_private_key_file_name hash.merge!(k => 'ssl_key.pem') + elsif integration == 'google_play' && k == :service_account_key + hash.merge!(k => File.read('spec/fixtures/service_account.json')) + elsif integration == 'google_play' && k == :service_account_key_file_name + hash.merge!(k => 'service_account.json') else hash.merge!(k => "someword") end -- GitLab From d20cdd5380aa6cec5d3d50db0c16a974815d6c60 Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Thu, 23 Feb 2023 20:06:15 -0600 Subject: [PATCH 13/19] Updated tests --- .../projects/integrations/google_play_spec.rb | 4 ++-- spec/models/integrations/google_play_spec.rb | 22 +++++++------------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/spec/features/projects/integrations/google_play_spec.rb b/spec/features/projects/integrations/google_play_spec.rb index e8a970076ac1dd..5db4bc8809fa5c 100644 --- a/spec/features/projects/integrations/google_play_spec.rb +++ b/spec/features/projects/integrations/google_play_spec.rb @@ -8,7 +8,7 @@ it 'uploads the file data to the correct form fields and updates the messaging correctly', :js, :aggregate_failures do visit_project_integration('Google Play') - expect(page).to have_content('Drag your Service Account Key file here or click to upload.') + expect(page).to have_content('Drag your key file here or click to upload.') expect(page).not_to have_content('service_account.json') find("input[name='service[dropzone_file_name]']", @@ -19,7 +19,7 @@ expect(find("input[name='service[service_account_key_file_name]']", visible: false).value).to eq('service_account.json') - expect(page).not_to have_content('Drag your Service Account Key file here or click to upload.') + expect(page).not_to have_content('Drag your key file here or click to upload.') expect(page).to have_content('service_account.json') end end diff --git a/spec/models/integrations/google_play_spec.rb b/spec/models/integrations/google_play_spec.rb index 254fde9d46e9a8..747087365979f2 100644 --- a/spec/models/integrations/google_play_spec.rb +++ b/spec/models/integrations/google_play_spec.rb @@ -3,21 +3,15 @@ require 'spec_helper' RSpec.describe Integrations::GooglePlay, feature_category: :mobile_devops do - context 'when validating the settings' do - let(:google_play_integration) { create(:google_play_integration) } - - it 'is valid when all the required values are provided' do - expect(google_play_integration.valid?).to be true - end - - it 'is invalid when the service account key does not match the expected format' do - google_play_integration.service_account_key = File.read('spec/fixtures/group.json') - expect(google_play_integration.valid?).to be false - end + describe 'Validations' do + context 'when active' do + before do + subject.active = true + end - it 'is invalid when the service_account_key_file_name is nil' do - google_play_integration.service_account_key_file_name = nil - expect(google_play_integration.valid?).to be false + it { is_expected.to validate_presence_of :service_account_key_file_name } + it { is_expected.to allow_value(File.read('spec/fixtures/service_account.json')).for(:service_account_key) } + it { is_expected.not_to allow_value(File.read('spec/fixtures/group.json')).for(:service_account_key) } end end -- GitLab From 98de85289d3ff1f59fe7e918ab18ade16cc73eaf Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Fri, 24 Feb 2023 10:39:06 -0600 Subject: [PATCH 14/19] Updated tests and json_schema validation --- app/models/integrations/google_play.rb | 17 +++--------- app/validators/json_schema_validator.rb | 1 + .../components/sections/google_play_spec.js | 27 +++++++++---------- spec/models/integrations/google_play_spec.rb | 6 +---- 4 files changed, 18 insertions(+), 33 deletions(-) diff --git a/app/models/integrations/google_play.rb b/app/models/integrations/google_play.rb index fa3172dfa4a461..7149f872a4ca85 100644 --- a/app/models/integrations/google_play.rb +++ b/app/models/integrations/google_play.rb @@ -4,11 +4,10 @@ module Integrations class GooglePlay < Integration SECTION_TYPE_GOOGLE_PLAY = 'google_play' - KEY_SCHEMA_PATH = 'app/validators/json_schemas/google_service_account_key.json' - KEY_SCHEMA = JSONSchemer.schema(Rails.root.join(KEY_SCHEMA_PATH)) - with_options if: :activated? do - validate :service_account_key, :valid_service_account_key? + validates :service_account_key, presence: true, json_schema: { + filename: "google_service_account_key", parse_json: true + } validates :service_account_key_file_name, presence: true end @@ -80,18 +79,10 @@ def ci_variables private def client - scopes = ['https://www.googleapis.com/auth/androidpublisher'] - Google::Auth::ServiceAccountCredentials.make_creds( json_key_io: StringIO.new(service_account_key), - scope: scopes + scope: ['https://www.googleapis.com/auth/androidpublisher'] ) end - - def valid_service_account_key? - return if KEY_SCHEMA.valid?(Gitlab::Json.parse(service_account_key)) - - errors.add(:service_account_key, "is not valid") - end end end diff --git a/app/validators/json_schema_validator.rb b/app/validators/json_schema_validator.rb index 4896c2ea2efbab..9c246a114f64d2 100644 --- a/app/validators/json_schema_validator.rb +++ b/app/validators/json_schema_validator.rb @@ -25,6 +25,7 @@ def initialize(options) def validate_each(record, attribute, value) value = value.to_h.stringify_keys if options[:hash_conversion] == true + value = Gitlab::Json.parse(value.to_s) if options[:parse_json] == true && !value.nil? unless valid_schema?(value) record.errors.add(attribute, _("must be a valid json schema")) diff --git a/spec/frontend/integrations/edit/components/sections/google_play_spec.js b/spec/frontend/integrations/edit/components/sections/google_play_spec.js index e9b9340d63c285..c0d6d17f639edd 100644 --- a/spec/frontend/integrations/edit/components/sections/google_play_spec.js +++ b/spec/frontend/integrations/edit/components/sections/google_play_spec.js @@ -7,31 +7,28 @@ import { createStore } from '~/integrations/edit/store'; describe('IntegrationSectionGooglePlay', () => { let wrapper; - const createComponent = (componentFields) => { + const createComponent = (fileName = '') => { const store = createStore({ - customState: { ...componentFields }, + customState: { + fields: [ + { + name: 'service_account_key_file_name', + value: fileName, + }, + ], + }, }); + wrapper = shallowMount(IntegrationSectionGooglePlay, { store, }); }; - const componentFields = (fileName = '') => { - return { - fields: [ - { - name: 'service_account_key_file_name', - value: fileName, - }, - ], - }; - }; - const findUploadDropzoneField = () => wrapper.findComponent(UploadDropzoneField); describe('computed properties', () => { it('renders UploadDropzoneField with default values', () => { - createComponent(componentFields()); + createComponent(); const field = findUploadDropzoneField(); @@ -43,7 +40,7 @@ describe('IntegrationSectionGooglePlay', () => { }); it('renders UploadDropzoneField with custom values for an attached file', () => { - createComponent(componentFields('fileName.txt')); + createComponent('fileName.txt'); const field = findUploadDropzoneField(); diff --git a/spec/models/integrations/google_play_spec.rb b/spec/models/integrations/google_play_spec.rb index 747087365979f2..ab1aaad24e7be3 100644 --- a/spec/models/integrations/google_play_spec.rb +++ b/spec/models/integrations/google_play_spec.rb @@ -10,6 +10,7 @@ end it { is_expected.to validate_presence_of :service_account_key_file_name } + it { is_expected.to validate_presence_of :service_account_key } it { is_expected.to allow_value(File.read('spec/fixtures/service_account.json')).for(:service_account_key) } it { is_expected.not_to allow_value(File.read('spec/fixtures/group.json')).for(:service_account_key) } end @@ -65,11 +66,6 @@ expect(google_play_integration.ci_variables).to match_array(ci_vars) end - - it 'returns an empty array when the integration is disabled' do - google_play_integration = build_stubbed(:google_play_integration, active: false) - expect(google_play_integration.ci_variables).to match_array([]) - end end end -- GitLab From 0250916990558e7fa8531404cacba9ea6904043e Mon Sep 17 00:00:00 2001 From: Ashraf Khamis Date: Fri, 24 Feb 2023 16:45:03 +0000 Subject: [PATCH 15/19] Applying suggested copy changes --- app/models/integrations/google_play.rb | 6 +++--- doc/user/project/integrations/google_play.md | 4 ++-- locale/gitlab.pot | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/models/integrations/google_play.rb b/app/models/integrations/google_play.rb index 7149f872a4ca85..f9072d018f88a5 100644 --- a/app/models/integrations/google_play.rb +++ b/app/models/integrations/google_play.rb @@ -33,10 +33,10 @@ def help # rubocop:disable Layout/LineLength texts = [ - s_("Use the Google Play integration to easily connect to Google Play with Fastlane in CI/CD pipelines."), - s_("After the Google Play integration is activated, the following protected variables will be created for CI/CD use."), + s_("Use the Google Play integration to connect to Google Play with fastlane in CI/CD pipelines."), + s_("After you enable the integration, the following protected variable is created for CI/CD use:"), variable_list.join('
'), - s_(format("To get started, see the integration documentation for instructions on how to generate a Google Play Service Account key, and how to use this integration.", url: "#")).html_safe + s_(format("To generate a Google Play service account key and use this integration, see the integration documentation.", url: "#")).html_safe ] # rubocop:enable Layout/LineLength diff --git a/doc/user/project/integrations/google_play.md b/doc/user/project/integrations/google_play.md index 83c4cd82363f70..246011d09d226f 100644 --- a/doc/user/project/integrations/google_play.md +++ b/doc/user/project/integrations/google_play.md @@ -28,10 +28,10 @@ To enable the Google Play integration in GitLab: 1. On the left sidebar, select **Settings > Integrations**. 1. Select **Google Play**. 1. In **Enable Integration**, select the **Active** checkbox. -1. In **Service account key**, drag or upload your key file. +1. In **Service account key (.json)**, drag or upload your key file. 1. Select **Save changes**. -After you enable the integration, the global variables `$SUPPLY_JSON_KEY_DATA` are created for CI/CD use. +After you enable the integration, the global variable `$SUPPLY_JSON_KEY_DATA` is created for CI/CD use. ### CI/CD variable security diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 97afbbcd189482..3d82300accfb65 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3702,7 +3702,7 @@ msgstr "" msgid "After the Apple App Store Connect integration is activated, the following protected variables will be created for CI/CD use." msgstr "" -msgid "After the Google Play integration is activated, the following protected variables will be created for CI/CD use." +msgid "After you enable the integration, the following protected variable is created for CI/CD use:" msgstr "" msgid "After the export is complete, download the data file from a notification email or from this page. You can then import the data file from the %{strong_text_start}Create new group%{strong_text_end} page of another GitLab instance." @@ -46450,7 +46450,7 @@ msgstr "" msgid "Use the Apple App Store Connect integration to easily connect to the Apple App Store with Fastlane in CI/CD pipelines." msgstr "" -msgid "Use the Google Play integration to easily connect to Google Play with Fastlane in CI/CD pipelines." +msgid "Use the Google Play integration to connect to Google Play with fastlane in CI/CD pipelines." msgstr "" msgid "Use the link below to confirm your email address (%{email})" -- GitLab From 77fb33ae21add2261ad30b0991e832ab36b5196c Mon Sep 17 00:00:00 2001 From: Ashraf Khamis Date: Fri, 24 Feb 2023 17:43:38 +0000 Subject: [PATCH 16/19] Applying copy update suggestions --- .../integrations/edit/components/sections/google_play.vue | 4 ++-- locale/gitlab.pot | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/integrations/edit/components/sections/google_play.vue b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue index fa814d59e38a9f..f75d49f2c604f4 100644 --- a/app/assets/javascripts/integrations/edit/components/sections/google_play.vue +++ b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue @@ -20,9 +20,9 @@ export default { 'GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}.', ), dropzoneErrorMessage: s__( - 'GooglePlay|Error: You are trying to upload something other than a Service Account Key file.', + 'GooglePlay|Error: The file you're trying to upload is not a service account key.', ), - dropzoneConfirmMessage: s__('GooglePlay|Drop your key file to start the upload.'), + dropzoneConfirmMessage: s__('GooglePlay|Drag your key file to start the upload.'), dropzoneEmptyInputName: s__('GooglePlay|Service account key (.json)'), dropzoneNonEmptyInputName: s__( 'GooglePlay|Upload a new service account key (replace %{currentFileName})', diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 3d82300accfb65..773b1495db7fb7 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -19655,10 +19655,10 @@ msgstr "" msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}." msgstr "" -msgid "GooglePlay|Drop your key file to start the upload." +msgid "GooglePlay|Drag your key file to start the upload." msgstr "" -msgid "GooglePlay|Error: You are trying to upload something other than a Service Account Key file." +msgid "GooglePlay|Error: The file you're trying to upload is not a service account key." msgstr "" msgid "GooglePlay|Leave empty to use your current service account key." -- GitLab From 252640ca68f69bd58f1ea442042ea8e084dc41d9 Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Fri, 24 Feb 2023 11:57:48 -0600 Subject: [PATCH 17/19] Updated translations --- .../integrations/edit/components/sections/google_play.vue | 2 +- doc/user/project/integrations/google_play.md | 2 +- locale/gitlab.pot | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/integrations/edit/components/sections/google_play.vue b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue index f75d49f2c604f4..3094e24241a62d 100644 --- a/app/assets/javascripts/integrations/edit/components/sections/google_play.vue +++ b/app/assets/javascripts/integrations/edit/components/sections/google_play.vue @@ -20,7 +20,7 @@ export default { 'GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}.', ), dropzoneErrorMessage: s__( - 'GooglePlay|Error: The file you're trying to upload is not a service account key.', + "GooglePlay|Error: The file you're trying to upload is not a service account key.", ), dropzoneConfirmMessage: s__('GooglePlay|Drag your key file to start the upload.'), dropzoneEmptyInputName: s__('GooglePlay|Service account key (.json)'), diff --git a/doc/user/project/integrations/google_play.md b/doc/user/project/integrations/google_play.md index 246011d09d226f..553e82be3828cc 100644 --- a/doc/user/project/integrations/google_play.md +++ b/doc/user/project/integrations/google_play.md @@ -28,7 +28,7 @@ To enable the Google Play integration in GitLab: 1. On the left sidebar, select **Settings > Integrations**. 1. Select **Google Play**. 1. In **Enable Integration**, select the **Active** checkbox. -1. In **Service account key (.json)**, drag or upload your key file. +1. In **Service account key (.JSON)**, drag or upload your key file. 1. Select **Save changes**. After you enable the integration, the global variable `$SUPPLY_JSON_KEY_DATA` is created for CI/CD use. diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 773b1495db7fb7..42cc4345dc9303 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3702,10 +3702,10 @@ msgstr "" msgid "After the Apple App Store Connect integration is activated, the following protected variables will be created for CI/CD use." msgstr "" -msgid "After you enable the integration, the following protected variable is created for CI/CD use:" +msgid "After the export is complete, download the data file from a notification email or from this page. You can then import the data file from the %{strong_text_start}Create new group%{strong_text_end} page of another GitLab instance." msgstr "" -msgid "After the export is complete, download the data file from a notification email or from this page. You can then import the data file from the %{strong_text_start}Create new group%{strong_text_end} page of another GitLab instance." +msgid "After you enable the integration, the following protected variable is created for CI/CD use:" msgstr "" msgid "After you've reviewed these contribution guidelines, you'll be all set to" -- GitLab From 3c6e466bd15d79f6280abdc0fabbcfcbd44fabc4 Mon Sep 17 00:00:00 2001 From: Sean Arnold Date: Mon, 27 Feb 2023 02:21:50 +0000 Subject: [PATCH 18/19] Applying suggestions --- app/models/integrations/google_play.rb | 2 +- spec/models/ci/build_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/integrations/google_play.rb b/app/models/integrations/google_play.rb index f9072d018f88a5..8f1d2e7e1ecd08 100644 --- a/app/models/integrations/google_play.rb +++ b/app/models/integrations/google_play.rb @@ -19,7 +19,7 @@ class GooglePlay < Integration field :service_account_key, api_only: true, is_secret: false def title - 'Google Play' + s_('GooglePlay|Google Play') end def description diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 86d02c0acb78d3..99c168de6165f4 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -3666,14 +3666,14 @@ build.project.update!(google_play_integration: google_play_integration) end - it 'does not include the googe_play variable' do + it 'does not include the google_play variable' do expect(subject[:key] == 'SUPPLY_JSON_KEY_DATA').to eq(false) end end end context 'when the googel_play integration does not exist' do - it 'does not include googel_play variable' do + it 'does not include google_play variable' do expect(subject[:key] == 'SUPPLY_JSON_KEY_DATA').to eq(false) end end -- GitLab From 790384bf3bda5421567cbc1e269b6332b0f0c4cd Mon Sep 17 00:00:00 2001 From: Darby Frey Date: Sun, 26 Feb 2023 20:30:21 -0600 Subject: [PATCH 19/19] Updated translations --- locale/gitlab.pot | 3 +++ 1 file changed, 3 insertions(+) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 42cc4345dc9303..2ad9741e3e8c4b 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -19661,6 +19661,9 @@ msgstr "" msgid "GooglePlay|Error: The file you're trying to upload is not a service account key." msgstr "" +msgid "GooglePlay|Google Play" +msgstr "" + msgid "GooglePlay|Leave empty to use your current service account key." msgstr "" -- GitLab