Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									b8d3aa799c
								
							
						
					
					
						commit
						aaa0fba820
					
				|  | @ -2,7 +2,7 @@ | ||||||
| import { GlModal, GlAlert } from '@gitlab/ui'; | import { GlModal, GlAlert } from '@gitlab/ui'; | ||||||
| import { mapGetters, mapActions, mapState } from 'vuex'; | import { mapGetters, mapActions, mapState } from 'vuex'; | ||||||
| import { TYPE_USER, TYPE_ITERATION, TYPE_MILESTONE } from '~/graphql_shared/constants'; | import { TYPE_USER, TYPE_ITERATION, TYPE_MILESTONE } from '~/graphql_shared/constants'; | ||||||
| import { convertToGraphQLId, getZeroBasedIdFromGraphQLId } from '~/graphql_shared/utils'; | import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils'; | ||||||
| import { getParameterByName, visitUrl } from '~/lib/utils/url_utility'; | import { getParameterByName, visitUrl } from '~/lib/utils/url_utility'; | ||||||
| import { __, s__ } from '~/locale'; | import { __, s__ } from '~/locale'; | ||||||
| import { fullLabelId } from '../boards_util'; | import { fullLabelId } from '../boards_util'; | ||||||
|  | @ -169,11 +169,11 @@ export default { | ||||||
|           : null, |           : null, | ||||||
|         // Temporarily converting to milestone ID due to https://gitlab.com/gitlab-org/gitlab/-/issues/344779 |         // Temporarily converting to milestone ID due to https://gitlab.com/gitlab-org/gitlab/-/issues/344779 | ||||||
|         milestoneId: this.board.milestone?.id |         milestoneId: this.board.milestone?.id | ||||||
|           ? convertToGraphQLId(TYPE_MILESTONE, getZeroBasedIdFromGraphQLId(this.board.milestone.id)) |           ? convertToGraphQLId(TYPE_MILESTONE, getIdFromGraphQLId(this.board.milestone.id)) | ||||||
|           : null, |           : null, | ||||||
|         // Temporarily converting to iteration ID due to https://gitlab.com/gitlab-org/gitlab/-/issues/344779 |         // Temporarily converting to iteration ID due to https://gitlab.com/gitlab-org/gitlab/-/issues/344779 | ||||||
|         iterationId: this.board.iteration?.id |         iterationId: this.board.iteration?.id | ||||||
|           ? convertToGraphQLId(TYPE_ITERATION, getZeroBasedIdFromGraphQLId(this.board.iteration.id)) |           ? convertToGraphQLId(TYPE_ITERATION, getIdFromGraphQLId(this.board.iteration.id)) | ||||||
|           : null, |           : null, | ||||||
|       }; |       }; | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|  | @ -268,12 +268,11 @@ export default { | ||||||
| <template> | <template> | ||||||
|   <div class="boards-switcher js-boards-selector gl-mr-3"> |   <div class="boards-switcher js-boards-selector gl-mr-3"> | ||||||
|     <span class="boards-selector-wrapper js-boards-selector-wrapper"> |     <span class="boards-selector-wrapper js-boards-selector-wrapper"> | ||||||
|       <gl-loading-icon v-if="isBoardLoading" size="md" class="gl-mt-2" /> |  | ||||||
|       <gl-dropdown |       <gl-dropdown | ||||||
|         v-else |  | ||||||
|         data-qa-selector="boards_dropdown" |         data-qa-selector="boards_dropdown" | ||||||
|         toggle-class="dropdown-menu-toggle js-dropdown-toggle" |         toggle-class="dropdown-menu-toggle js-dropdown-toggle" | ||||||
|         menu-class="flex-column dropdown-extended-height" |         menu-class="flex-column dropdown-extended-height" | ||||||
|  |         :loading="isBoardLoading" | ||||||
|         :text="board.name" |         :text="board.name" | ||||||
|         @show="loadBoards" |         @show="loadBoards" | ||||||
|       > |       > | ||||||
|  |  | ||||||
|  | @ -1,14 +1,27 @@ | ||||||
|  | import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; | ||||||
| import Vue from 'vue'; | import Vue from 'vue'; | ||||||
| import VueApollo from 'vue-apollo'; | import VueApollo from 'vue-apollo'; | ||||||
| import BoardsSelector from 'ee_else_ce/boards/components/boards_selector.vue'; | import BoardsSelector from 'ee_else_ce/boards/components/boards_selector.vue'; | ||||||
| import store from '~/boards/stores'; | import store from '~/boards/stores'; | ||||||
| import createDefaultClient from '~/lib/graphql'; | import createDefaultClient from '~/lib/graphql'; | ||||||
| import { parseBoolean } from '~/lib/utils/common_utils'; | import { parseBoolean } from '~/lib/utils/common_utils'; | ||||||
|  | import introspectionQueryResultData from '~/sidebar/fragmentTypes.json'; | ||||||
| 
 | 
 | ||||||
| Vue.use(VueApollo); | Vue.use(VueApollo); | ||||||
| 
 | 
 | ||||||
|  | const fragmentMatcher = new IntrospectionFragmentMatcher({ | ||||||
|  |   introspectionQueryResultData, | ||||||
|  | }); | ||||||
|  | 
 | ||||||
| const apolloProvider = new VueApollo({ | const apolloProvider = new VueApollo({ | ||||||
|   defaultClient: createDefaultClient(), |   defaultClient: createDefaultClient( | ||||||
|  |     {}, | ||||||
|  |     { | ||||||
|  |       cacheConfig: { | ||||||
|  |         fragmentMatcher, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ), | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| export default (params = {}) => { | export default (params = {}) => { | ||||||
|  |  | ||||||
|  | @ -6,14 +6,6 @@ const elementRenderer = (element, props = {}) => (createElement) => | ||||||
| 
 | 
 | ||||||
| export default () => { | export default () => { | ||||||
|   const root = document.querySelector('#js-google-cloud'); |   const root = document.querySelector('#js-google-cloud'); | ||||||
| 
 |   const props = JSON.parse(root.getAttribute('data')); | ||||||
|   // uncomment this once backend is ready
 |   return new Vue({ el: root, render: elementRenderer(App, props) }); | ||||||
|   // const dataset = JSON.parse(root.getAttribute('data'));
 |  | ||||||
|   const mockDataset = { |  | ||||||
|     createServiceAccountUrl: '#create-url', |  | ||||||
|     serviceAccounts: [], |  | ||||||
|     emptyIllustrationUrl: |  | ||||||
|       'https://gitlab.com/gitlab-org/gitlab-svgs/-/raw/main/illustrations/pipelines_empty.svg', |  | ||||||
|   }; |  | ||||||
|   return new Vue({ el: root, render: elementRenderer(App, mockDataset) }); |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -25,9 +25,7 @@ const parseGid = (gid) => parseInt(`${gid}`.replace(/gid:\/\/gitlab\/.*\//g, '') | ||||||
|  * @param {String} gid GraphQL global ID |  * @param {String} gid GraphQL global ID | ||||||
|  * @returns {Number} |  * @returns {Number} | ||||||
|  */ |  */ | ||||||
| export const getIdFromGraphQLId = (gid = '') => parseGid(gid) || null; | export const getIdFromGraphQLId = (gid = '') => { | ||||||
| 
 |  | ||||||
| export const getZeroBasedIdFromGraphQLId = (gid = '') => { |  | ||||||
|   const parsedGid = parseGid(gid); |   const parsedGid = parseGid(gid); | ||||||
|   return Number.isInteger(parsedGid) ? parsedGid : null; |   return Number.isInteger(parsedGid) ? parsedGid : null; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -8,6 +8,11 @@ class Projects::GoogleCloudController < Projects::ApplicationController | ||||||
|   before_action :feature_flag_enabled? |   before_action :feature_flag_enabled? | ||||||
| 
 | 
 | ||||||
|   def index |   def index | ||||||
|  |     @js_data = { | ||||||
|  |       serviceAccounts: GoogleCloud::ServiceAccountsService.new(project).find_for_project, | ||||||
|  |       createServiceAccountUrl: '#mocked-url-create-service', | ||||||
|  |       emptyIllustrationUrl: ActionController::Base.helpers.image_path('illustrations/pipelines_empty.svg') | ||||||
|  |     }.to_json | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   private |   private | ||||||
|  |  | ||||||
|  | @ -0,0 +1,40 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | module GoogleCloud | ||||||
|  |   ## | ||||||
|  |   # GCP keys used to store Google Cloud Service Accounts | ||||||
|  |   GCP_KEYS = %w[GCP_PROJECT_ID GCP_SERVICE_ACCOUNT GCP_SERVICE_ACCOUNT_KEY].freeze | ||||||
|  | 
 | ||||||
|  |   ## | ||||||
|  |   # This service deals with GCP Service Accounts in GitLab | ||||||
|  | 
 | ||||||
|  |   class ServiceAccountsService < ::BaseService | ||||||
|  |     ## | ||||||
|  |     # Find GCP Service Accounts in a GitLab project | ||||||
|  |     # | ||||||
|  |     # This method looks up GitLab project's CI vars | ||||||
|  |     # and returns Google Cloud Service Accounts combinations | ||||||
|  |     # aligning GitLab project and environment to GCP projects | ||||||
|  | 
 | ||||||
|  |     def find_for_project | ||||||
|  |       group_vars_by_environment.map do |environment_scope, value| | ||||||
|  |         { | ||||||
|  |           environment: environment_scope, | ||||||
|  |           gcp_project: value['GCP_PROJECT_ID'], | ||||||
|  |           service_account_exists: value['GCP_SERVICE_ACCOUNT'].present?, | ||||||
|  |           service_account_key_exists: value['GCP_SERVICE_ACCOUNT_KEY'].present? | ||||||
|  |         } | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     private | ||||||
|  | 
 | ||||||
|  |     def group_vars_by_environment | ||||||
|  |       filtered_vars = @project.variables.filter { |variable| GCP_KEYS.include? variable.key } | ||||||
|  |       filtered_vars.each_with_object({}) do |variable, grouped| | ||||||
|  |         grouped[variable.environment_scope] ||= {} | ||||||
|  |         grouped[variable.environment_scope][variable.key] = variable.value | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -3,4 +3,4 @@ | ||||||
| 
 | 
 | ||||||
| - @content_class = "limit-container-width" unless fluid_layout | - @content_class = "limit-container-width" unless fluid_layout | ||||||
| 
 | 
 | ||||||
| #js-google-cloud | #js-google-cloud{ data: @js_data } | ||||||
|  |  | ||||||
|  | @ -1,4 +1,6 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| # Currently we register validator only for `dev` or `test` environment | # Currently we register validator only for `dev` or `test` environment | ||||||
| Gitlab::Database::QueryAnalyzer.new.hook! if Gitlab.dev_or_test_env? | if Gitlab.dev_or_test_env? || Gitlab::Utils.to_boolean(ENV['GITLAB_ENABLE_QUERY_ANALYZERS'], default: false) | ||||||
|  |   Gitlab::Database::QueryAnalyzer.instance.hook! | ||||||
|  | end | ||||||
|  |  | ||||||
|  | @ -2599,33 +2599,12 @@ faster-test-job: | ||||||
|     - echo "Running tests..." |     - echo "Running tests..." | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ### `artifacts` | ### `dependencies` | ||||||
| 
 | 
 | ||||||
| Use `artifacts` to specify a list of files and directories that are | Use the `dependencies` keyword to define a list of jobs to fetch [artifacts](#artifacts) from. | ||||||
| attached to the job when it [succeeds, fails, or always](#artifactswhen). |  | ||||||
| 
 |  | ||||||
| The artifacts are sent to GitLab after the job finishes. They are |  | ||||||
| available for download in the GitLab UI if the size is not |  | ||||||
| larger than the [maximum artifact size](../../user/gitlab_com/index.md#gitlab-cicd). |  | ||||||
| 
 |  | ||||||
| By default, jobs in later stages automatically download all the artifacts created |  | ||||||
| by jobs in earlier stages. You can control artifact download behavior in jobs with |  | ||||||
| [`dependencies`](#dependencies). |  | ||||||
| 
 |  | ||||||
| When using the [`needs`](#artifact-downloads-with-needs) keyword, jobs can only download |  | ||||||
| artifacts from the jobs defined in the `needs` configuration. |  | ||||||
| 
 |  | ||||||
| Job artifacts are only collected for successful jobs by default, and |  | ||||||
| artifacts are restored after [caches](#cache). |  | ||||||
| 
 |  | ||||||
| [Read more about artifacts](../pipelines/job_artifacts.md). |  | ||||||
| 
 |  | ||||||
| #### `dependencies` |  | ||||||
| 
 |  | ||||||
| Use the `dependencies` keyword to define a list of jobs to fetch artifacts from. |  | ||||||
| You can also set a job to download no artifacts at all. | You can also set a job to download no artifacts at all. | ||||||
| 
 | 
 | ||||||
| If you do not use `dependencies`, all `artifacts` from previous stages are passed to each job. | If you do not use `dependencies`, all artifacts from previous stages are passed to each job. | ||||||
| 
 | 
 | ||||||
| **Keyword type**: Job keyword. You can use it only as part of a job. | **Keyword type**: Job keyword. You can use it only as part of a job. | ||||||
| 
 | 
 | ||||||
|  | @ -2681,6 +2660,27 @@ the [stage](#stages) precedence. | ||||||
| - If the artifacts of a dependent job are [expired](#artifactsexpire_in) or | - If the artifacts of a dependent job are [expired](#artifactsexpire_in) or | ||||||
|   [deleted](../pipelines/job_artifacts.md#delete-job-artifacts), then the job fails. |   [deleted](../pipelines/job_artifacts.md#delete-job-artifacts), then the job fails. | ||||||
| 
 | 
 | ||||||
|  | ### `artifacts` | ||||||
|  | 
 | ||||||
|  | Use `artifacts` to specify a list of files and directories that are | ||||||
|  | attached to the job when it [succeeds, fails, or always](#artifactswhen). | ||||||
|  | 
 | ||||||
|  | The artifacts are sent to GitLab after the job finishes. They are | ||||||
|  | available for download in the GitLab UI if the size is not | ||||||
|  | larger than the [maximum artifact size](../../user/gitlab_com/index.md#gitlab-cicd). | ||||||
|  | 
 | ||||||
|  | By default, jobs in later stages automatically download all the artifacts created | ||||||
|  | by jobs in earlier stages. You can control artifact download behavior in jobs with | ||||||
|  | [`dependencies`](#dependencies). | ||||||
|  | 
 | ||||||
|  | When using the [`needs`](#artifact-downloads-with-needs) keyword, jobs can only download | ||||||
|  | artifacts from the jobs defined in the `needs` configuration. | ||||||
|  | 
 | ||||||
|  | Job artifacts are only collected for successful jobs by default, and | ||||||
|  | artifacts are restored after [caches](#cache). | ||||||
|  | 
 | ||||||
|  | [Read more about artifacts](../pipelines/job_artifacts.md). | ||||||
|  | 
 | ||||||
| #### `artifacts:exclude` | #### `artifacts:exclude` | ||||||
| 
 | 
 | ||||||
| > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15122) in GitLab 13.1 | > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15122) in GitLab 13.1 | ||||||
|  |  | ||||||
|  | @ -118,8 +118,9 @@ SSO has the following effects when enabled: | ||||||
| 
 | 
 | ||||||
| - For groups, users can't share a project in the group outside the top-level group, | - For groups, users can't share a project in the group outside the top-level group, | ||||||
|   even if the project is forked. |   even if the project is forked. | ||||||
| - For a Git activity, users must be signed-in through SSO before they can push to or | - For Git activity over SSH and HTTPS, users must have at least one active session signed-in through SSO before they can push to or | ||||||
|   pull from a GitLab repository. |   pull from a GitLab repository.  | ||||||
|  | - Credentials that are not tied to regular users (for example, access tokens and deploy keys) do not have the SSO check enforced. | ||||||
| - Users must be signed-in through SSO before they can pull images using the [Dependency Proxy](../../packages/dependency_proxy/index.md). | - Users must be signed-in through SSO before they can pull images using the [Dependency Proxy](../../packages/dependency_proxy/index.md). | ||||||
| <!-- Add bullet for API activity when https://gitlab.com/gitlab-org/gitlab/-/issues/9152 is complete --> | <!-- Add bullet for API activity when https://gitlab.com/gitlab-org/gitlab/-/issues/9152 is complete --> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -66,7 +66,7 @@ module Gitlab | ||||||
|                 # times before using the primary instead. |                 # times before using the primary instead. | ||||||
|                 will_retry = conflict_retried < @host_list.length * 3 |                 will_retry = conflict_retried < @host_list.length * 3 | ||||||
| 
 | 
 | ||||||
|                 LoadBalancing::Logger.warn( |                 ::Gitlab::Database::LoadBalancing::Logger.warn( | ||||||
|                   event: :host_query_conflict, |                   event: :host_query_conflict, | ||||||
|                   message: 'Query conflict on host', |                   message: 'Query conflict on host', | ||||||
|                   conflict_retried: conflict_retried, |                   conflict_retried: conflict_retried, | ||||||
|  | @ -91,7 +91,7 @@ module Gitlab | ||||||
|             end |             end | ||||||
|           end |           end | ||||||
| 
 | 
 | ||||||
|           LoadBalancing::Logger.warn( |           ::Gitlab::Database::LoadBalancing::Logger.warn( | ||||||
|             event: :no_secondaries_available, |             event: :no_secondaries_available, | ||||||
|             message: 'No secondaries were available, using primary instead', |             message: 'No secondaries were available, using primary instead', | ||||||
|             conflict_retried: conflict_retried, |             conflict_retried: conflict_retried, | ||||||
|  |  | ||||||
|  | @ -13,7 +13,7 @@ module Gitlab | ||||||
|           job['load_balancing_strategy'] = strategy.to_s |           job['load_balancing_strategy'] = strategy.to_s | ||||||
| 
 | 
 | ||||||
|           if use_primary?(strategy) |           if use_primary?(strategy) | ||||||
|             Session.current.use_primary! |             ::Gitlab::Database::LoadBalancing::Session.current.use_primary! | ||||||
|           elsif strategy == :retry |           elsif strategy == :retry | ||||||
|             raise JobReplicaNotUpToDate, "Sidekiq job #{worker_class} JID-#{job['jid']} couldn't use the replica."\ |             raise JobReplicaNotUpToDate, "Sidekiq job #{worker_class} JID-#{job['jid']} couldn't use the replica."\ | ||||||
|               "  Replica was not up to date." |               "  Replica was not up to date." | ||||||
|  | @ -29,8 +29,8 @@ module Gitlab | ||||||
|         private |         private | ||||||
| 
 | 
 | ||||||
|         def clear |         def clear | ||||||
|           LoadBalancing.release_hosts |           ::Gitlab::Database::LoadBalancing.release_hosts | ||||||
|           Session.clear_session |           ::Gitlab::Database::LoadBalancing::Session.clear_session | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         def use_primary?(strategy) |         def use_primary?(strategy) | ||||||
|  | @ -66,7 +66,7 @@ module Gitlab | ||||||
|         def legacy_wal_location(job) |         def legacy_wal_location(job) | ||||||
|           wal_location = job['database_write_location'] || job['database_replica_location'] |           wal_location = job['database_write_location'] || job['database_replica_location'] | ||||||
| 
 | 
 | ||||||
|           { Gitlab::Database::MAIN_DATABASE_NAME.to_sym => wal_location } if wal_location |           { ::Gitlab::Database::MAIN_DATABASE_NAME.to_sym => wal_location } if wal_location | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         def load_balancing_available?(worker_class) |         def load_balancing_available?(worker_class) | ||||||
|  | @ -90,7 +90,7 @@ module Gitlab | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         def databases_in_sync?(wal_locations) |         def databases_in_sync?(wal_locations) | ||||||
|           LoadBalancing.each_load_balancer.all? do |lb| |           ::Gitlab::Database::LoadBalancing.each_load_balancer.all? do |lb| | ||||||
|             if (location = wal_locations[lb.name]) |             if (location = wal_locations[lb.name]) | ||||||
|               lb.select_up_to_date_host(location) |               lb.select_up_to_date_host(location) | ||||||
|             else |             else | ||||||
|  |  | ||||||
|  | @ -5,6 +5,8 @@ module Gitlab | ||||||
|     # The purpose of this class is to implement a various query analyzers based on `pg_query` |     # The purpose of this class is to implement a various query analyzers based on `pg_query` | ||||||
|     # And process them all via `Gitlab::Database::QueryAnalyzers::*` |     # And process them all via `Gitlab::Database::QueryAnalyzers::*` | ||||||
|     class QueryAnalyzer |     class QueryAnalyzer | ||||||
|  |       include ::Singleton | ||||||
|  | 
 | ||||||
|       ANALYZERS = [].freeze |       ANALYZERS = [].freeze | ||||||
| 
 | 
 | ||||||
|       Parsed = Struct.new( |       Parsed = Struct.new( | ||||||
|  |  | ||||||
|  | @ -1,7 +1,6 @@ | ||||||
| import { | import { | ||||||
|   isGid, |   isGid, | ||||||
|   getIdFromGraphQLId, |   getIdFromGraphQLId, | ||||||
|   getZeroBasedIdFromGraphQLId, |  | ||||||
|   convertToGraphQLId, |   convertToGraphQLId, | ||||||
|   convertToGraphQLIds, |   convertToGraphQLIds, | ||||||
|   convertFromGraphQLIds, |   convertFromGraphQLIds, | ||||||
|  | @ -54,7 +53,7 @@ describe('getIdFromGraphQLId', () => { | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|       input: 'gid://gitlab/Environments/0', |       input: 'gid://gitlab/Environments/0', | ||||||
|       output: null, |       output: 0, | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|       input: 'gid://gitlab/Environments/123', |       input: 'gid://gitlab/Environments/123', | ||||||
|  | @ -71,55 +70,6 @@ describe('getIdFromGraphQLId', () => { | ||||||
|   }); |   }); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| describe('getZeroBasedIdFromGraphQLId', () => { |  | ||||||
|   [ |  | ||||||
|     { |  | ||||||
|       input: '', |  | ||||||
|       output: null, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       input: null, |  | ||||||
|       output: null, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       input: 2, |  | ||||||
|       output: 2, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       input: 'gid://', |  | ||||||
|       output: null, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       input: 'gid://gitlab/', |  | ||||||
|       output: null, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       input: 'gid://gitlab/Environments', |  | ||||||
|       output: null, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       input: 'gid://gitlab/Environments/', |  | ||||||
|       output: null, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       input: 'gid://gitlab/Environments/0', |  | ||||||
|       output: 0, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       input: 'gid://gitlab/Environments/123', |  | ||||||
|       output: 123, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       input: 'gid://gitlab/DesignManagement::Version/2', |  | ||||||
|       output: 2, |  | ||||||
|     }, |  | ||||||
|   ].forEach(({ input, output }) => { |  | ||||||
|     it(`getZeroBasedIdFromGraphQLId returns ${output} when passed ${input}`, () => { |  | ||||||
|       expect(getZeroBasedIdFromGraphQLId(input)).toBe(output); |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| describe('convertToGraphQLId', () => { | describe('convertToGraphQLId', () => { | ||||||
|   it('combines $type and $id into $result', () => { |   it('combines $type and $id into $result', () => { | ||||||
|     expect(convertToGraphQLId(mockType, mockId)).toBe(mockGid); |     expect(convertToGraphQLId(mockType, mockId)).toBe(mockGid); | ||||||
|  |  | ||||||
|  | @ -65,7 +65,7 @@ RSpec.describe Gitlab::Database::QueryAnalyzer do | ||||||
| 
 | 
 | ||||||
|     def process_sql(sql) |     def process_sql(sql) | ||||||
|       ApplicationRecord.load_balancer.read_write do |connection| |       ApplicationRecord.load_balancer.read_write do |connection| | ||||||
|         described_class.new.send(:process_sql, sql, connection) |         described_class.instance.send(:process_sql, sql, connection) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -0,0 +1,58 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | require 'spec_helper' | ||||||
|  | 
 | ||||||
|  | RSpec.describe GoogleCloud::ServiceAccountsService do | ||||||
|  |   let_it_be(:project) { create(:project) } | ||||||
|  | 
 | ||||||
|  |   let(:service) { described_class.new(project) } | ||||||
|  | 
 | ||||||
|  |   describe 'find_for_project' do | ||||||
|  |     context 'when a project does not have GCP service account vars' do | ||||||
|  |       before do | ||||||
|  |         project.variables.build(key: 'blah', value: 'foo', environment_scope: 'world') | ||||||
|  |         project.save! | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'returns an empty list' do | ||||||
|  |         expect(service.find_for_project.length).to eq(0) | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'when a project has GCP service account ci vars' do | ||||||
|  |       before do | ||||||
|  |         project.variables.build(environment_scope: '*', key: 'GCP_PROJECT_ID', value: 'prj1') | ||||||
|  |         project.variables.build(environment_scope: '*', key: 'GCP_SERVICE_ACCOUNT_KEY', value: 'mock') | ||||||
|  |         project.variables.build(environment_scope: 'staging', key: 'GCP_PROJECT_ID', value: 'prj2') | ||||||
|  |         project.variables.build(environment_scope: 'staging', key: 'GCP_SERVICE_ACCOUNT', value: 'mock') | ||||||
|  |         project.variables.build(environment_scope: 'production', key: 'GCP_PROJECT_ID', value: 'prj3') | ||||||
|  |         project.variables.build(environment_scope: 'production', key: 'GCP_SERVICE_ACCOUNT', value: 'mock') | ||||||
|  |         project.variables.build(environment_scope: 'production', key: 'GCP_SERVICE_ACCOUNT_KEY', value: 'mock') | ||||||
|  |         project.save! | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'returns a list of service accounts' do | ||||||
|  |         list = service.find_for_project | ||||||
|  | 
 | ||||||
|  |         aggregate_failures 'testing list of service accounts' do | ||||||
|  |           expect(list.length).to eq(3) | ||||||
|  | 
 | ||||||
|  |           expect(list.first[:environment]).to eq('*') | ||||||
|  |           expect(list.first[:gcp_project]).to eq('prj1') | ||||||
|  |           expect(list.first[:service_account_exists]).to eq(false) | ||||||
|  |           expect(list.first[:service_account_key_exists]).to eq(true) | ||||||
|  | 
 | ||||||
|  |           expect(list.second[:environment]).to eq('staging') | ||||||
|  |           expect(list.second[:gcp_project]).to eq('prj2') | ||||||
|  |           expect(list.second[:service_account_exists]).to eq(true) | ||||||
|  |           expect(list.second[:service_account_key_exists]).to eq(false) | ||||||
|  | 
 | ||||||
|  |           expect(list.third[:environment]).to eq('production') | ||||||
|  |           expect(list.third[:gcp_project]).to eq('prj3') | ||||||
|  |           expect(list.third[:service_account_exists]).to eq(true) | ||||||
|  |           expect(list.third[:service_account_key_exists]).to eq(true) | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
		Loading…
	
		Reference in New Issue