diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-01 18:08:33 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-01 18:08:33 +0000 |
commit | 24d67ec55454fc6f4e8e80bf7c8dc5bc677e8514 (patch) | |
tree | 6ce73c2fd8ec96c6f043c4a1403c0991fd448b81 /app | |
parent | a0fdcfcdd514c2af98f18cadfa75f8a6a85b4d2c (diff) | |
download | gitlab-ce-24d67ec55454fc6f4e8e80bf7c8dc5bc677e8514.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
25 files changed, 177 insertions, 180 deletions
diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/included_in_trial_indicator.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/included_in_trial_indicator.vue new file mode 100644 index 00000000000..693dc6a15ad --- /dev/null +++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/included_in_trial_indicator.vue @@ -0,0 +1,15 @@ +<script> +import { s__ } from '~/locale'; + +export default { + name: 'IncludedInTrialIndicator', + i18n: { + trialOnly: s__('LearnGitlab|- Included in trial'), + }, +}; +</script> +<template> + <span class="gl-font-style-italic gl-text-gray-500" data-testid="trial-only"> + {{ $options.i18n.trialOnly }} + </span> +</template> diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab.vue index db9ef4df8af..54e15b6552c 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab.vue +++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab.vue @@ -38,14 +38,16 @@ export default { actionsData: this.actions, }; }, - maxValue: Object.keys(ACTION_LABELS).length, actionSections: Object.keys(ACTION_SECTIONS), computed: { + maxValue() { + return Object.keys(this.actionsData).length; + }, progressValue() { return Object.values(this.actionsData).filter((a) => a.completed).length; }, progressPercentage() { - return Math.round((this.progressValue / this.$options.maxValue) * 100); + return Math.round((this.progressValue / this.maxValue) * 100); }, }, mounted() { @@ -125,7 +127,7 @@ export default { <template #percentSymbol>%</template> </gl-sprintf> </p> - <gl-progress-bar :value="progressValue" :max="$options.maxValue" /> + <gl-progress-bar :value="progressValue" :max="maxValue" /> </div> <div class="row"> <div diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_info_card.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_info_card.vue deleted file mode 100644 index 09cc0032871..00000000000 --- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_info_card.vue +++ /dev/null @@ -1,70 +0,0 @@ -<script> -import { GlLink, GlCard, GlIcon } from '@gitlab/ui'; -import { s__ } from '~/locale'; - -export default { - name: 'LearnGitlabInfoCard', - components: { GlLink, GlCard, GlIcon }, - i18n: { - trial: s__('Learn GitLab|Trial only'), - }, - props: { - title: { - required: true, - type: String, - }, - description: { - required: true, - type: String, - }, - actionLabel: { - required: true, - type: String, - }, - url: { - required: true, - type: String, - }, - completed: { - required: true, - type: Boolean, - }, - svg: { - required: true, - type: String, - }, - trialRequired: { - default: false, - required: false, - type: Boolean, - }, - }, -}; -</script> -<template> - <gl-card class="gl-pt-0"> - <div class="gl-text-right gl-h-5"> - <gl-icon - v-if="completed" - name="check-circle-filled" - class="gl-text-green-500" - :size="16" - data-testid="completed-icon" - /> - <span - v-else-if="trialRequired" - class="gl-text-gray-500 gl-font-sm gl-font-style-italic" - data-testid="trial-only" - >{{ $options.i18n.trial }}</span - > - </div> - <div - class="gl-text-center gl-display-flex gl-justify-content-center gl-align-items-center gl-flex-direction-column learn-gitlab-info-card-content" - > - <img :src="svg" :alt="actionLabel" /> - <h6>{{ title }}</h6> - <p class="gl-font-sm gl-text-gray-700">{{ description }}</p> - <gl-link :href="url" target="_blank" rel="noopener noreferrer" /> - </div> - </gl-card> -</template> diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue index 1912477758b..4eab0cccb06 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue +++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue @@ -6,6 +6,7 @@ import { isExperimentVariant } from '~/experimentation/utils'; import eventHub from '~/invite_members/event_hub'; import { s__, __ } from '~/locale'; import { ACTION_LABELS } from '../constants'; +import IncludedInTrialIndicator from './included_in_trial_indicator.vue'; export default { name: 'LearnGitlabSectionLink', @@ -15,12 +16,12 @@ export default { GlButton, GlPopover, GitlabExperiment, + IncludedInTrialIndicator, }, directives: { GlTooltip, }, i18n: { - trialOnly: s__('LearnGitlab|Trial only'), contactAdmin: s__('LearnGitlab|Contact your administrator to start a free Ultimate trial.'), viewAdminList: s__('LearnGitlab|View administrator list'), watchHow: __('Watch how'), @@ -41,12 +42,6 @@ export default { }; }, computed: { - linkTitle() { - return ACTION_LABELS[this.action].title; - }, - trialOnly() { - return ACTION_LABELS[this.action].trialRequired; - }, showInviteModalLink() { return ( this.action === 'userAdded' && isExperimentVariant('invite_for_help_continuous_onboarding') @@ -55,49 +50,51 @@ export default { openInNewTab() { return ACTION_LABELS[this.action]?.openInNewTab === true || this.value.openInNewTab === true; }, - linkToVideoTutorial() { - return ACTION_LABELS[this.action].videoTutorial; - }, }, methods: { openModal() { eventHub.$emit('openModal', { source: 'learn_gitlab' }); }, + actionLabelValue(value) { + return ACTION_LABELS[this.action][value]; + }, }, }; </script> <template> <div class="gl-mb-4"> - <div v-if="trialOnly" class="gl-font-style-italic gl-text-gray-500" data-testid="trial-only"> - {{ $options.i18n.trialOnly }} - </div> <div class="flex align-items-center"> <span v-if="value.completed" class="gl-text-green-500"> <gl-icon name="check-circle-filled" :size="16" data-testid="completed-icon" /> - {{ linkTitle }} + {{ actionLabelValue('title') }} + <included-in-trial-indicator v-if="actionLabelValue('trialRequired')" /> </span> - <gl-link - v-else-if="showInviteModalLink" - data-track-action="click_link" - :data-track-label="linkTitle" - data-track-property="Growth::Activation::Experiment::InviteForHelpContinuousOnboarding" - data-testid="invite-for-help-continuous-onboarding-experiment-link" - @click="openModal" - > - {{ linkTitle }} - </gl-link> - <gl-link - v-else-if="value.enabled" - :target="openInNewTab ? '_blank' : '_self'" - :href="value.url" - data-testid="uncompleted-learn-gitlab-link" - data-track-action="click_link" - :data-track-label="linkTitle" - > - {{ linkTitle }} - </gl-link> + <div v-else-if="showInviteModalLink"> + <gl-link + data-track-action="click_link" + :data-track-label="actionLabelValue('trackLabel')" + data-track-property="Growth::Activation::Experiment::InviteForHelpContinuousOnboarding" + data-testid="invite-for-help-continuous-onboarding-experiment-link" + @click="openModal" + >{{ actionLabelValue('title') }}</gl-link + > + + <included-in-trial-indicator v-if="actionLabelValue('trialRequired')" /> + </div> + <div v-else-if="value.enabled"> + <gl-link + :target="openInNewTab ? '_blank' : '_self'" + :href="value.url" + data-testid="uncompleted-learn-gitlab-link" + data-track-action="click_link" + :data-track-label="actionLabelValue('trackLabel')" + >{{ actionLabelValue('title') }}</gl-link + > + + <included-in-trial-indicator v-if="actionLabelValue('trialRequired')" /> + </div> <template v-else> - <div data-testid="disabled-learn-gitlab-link">{{ linkTitle }}</div> + <div data-testid="disabled-learn-gitlab-link">{{ actionLabelValue('title') }}</div> <gl-button :id="popoverId" category="tertiary" @@ -127,19 +124,19 @@ export default { <template #control></template> <template #candidate> <gl-button - v-if="linkToVideoTutorial" + v-if="actionLabelValue('videoTutorial')" v-gl-tooltip category="tertiary" icon="live-preview" :title="$options.i18n.watchHow" :aria-label="$options.i18n.watchHow" - :href="linkToVideoTutorial" + :href="actionLabelValue('videoTutorial')" target="_blank" class="ml-auto" size="small" data-testid="video-tutorial-link" data-track-action="click_video_link" - :data-track-label="linkTitle" + :data-track-label="actionLabelValue('trackLabel')" data-track-property="Growth::Conversion::Experiment::LearnGitLab" data-track-experiment="video_tutorials_continuous_onboarding" /> diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js b/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js index 05bacd9b350..cb1a0302d91 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js +++ b/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js @@ -2,9 +2,10 @@ import { s__ } from '~/locale'; export const ACTION_LABELS = { gitWrite: { - title: s__('LearnGitLab|Create or import a repository'), - actionLabel: s__('LearnGitLab|Create or import a repository'), + title: s__('LearnGitLab|Create a repository'), + actionLabel: s__('LearnGitLab|Create a repository'), description: s__('LearnGitLab|Create or import your first repository into your new project.'), + trackLabel: 'create_a_repository', section: 'workspace', position: 1, }, @@ -14,20 +15,23 @@ export const ACTION_LABELS = { description: s__( 'LearnGitLab|GitLab works best as a team. Invite your colleague to enjoy all features.', ), + trackLabel: 'invite_your_colleagues', section: 'workspace', position: 0, }, pipelineCreated: { - title: s__('LearnGitLab|Set up CI/CD'), - actionLabel: s__('LearnGitLab|Set-up CI/CD'), + title: s__("LearnGitLab|Set up your first project's CI/CD"), + actionLabel: s__('LearnGitLab|Set up CI/CD'), description: s__('LearnGitLab|Save time by automating your integration and deployment tasks.'), + trackLabel: 'set_up_your_first_project_s_ci_cd', section: 'workspace', position: 2, }, trialStarted: { - title: s__('LearnGitLab|Start a free Ultimate trial'), + title: s__('LearnGitLab|Start a free trial of GitLab Ultimate'), actionLabel: s__('LearnGitLab|Try GitLab Ultimate for free'), description: s__('LearnGitLab|Try all GitLab features for 30 days, no credit card required.'), + trackLabel: 'start_a_free_trial_of_gitlab_ultimate', section: 'workspace', position: 3, openInNewTab: true, @@ -38,6 +42,7 @@ export const ACTION_LABELS = { description: s__( 'LearnGitLab|Prevent unexpected changes to important assets by assigning ownership of files and paths.', ), + trackLabel: 'add_code_owners', trialRequired: true, section: 'workspace', position: 4, @@ -45,9 +50,10 @@ export const ACTION_LABELS = { videoTutorial: 'https://vimeo.com/670896787', }, requiredMrApprovalsEnabled: { - title: s__('LearnGitLab|Add merge request approval'), + title: s__('LearnGitLab|Enable require merge approvals'), actionLabel: s__('LearnGitLab|Enable require merge approvals'), description: s__('LearnGitLab|Route code reviews to the right reviewers, every time.'), + trackLabel: 'enable_require_merge_approvals', trialRequired: true, section: 'workspace', position: 5, @@ -55,28 +61,52 @@ export const ACTION_LABELS = { videoTutorial: 'https://vimeo.com/670904904', }, mergeRequestCreated: { - title: s__('LearnGitLab|Submit a merge request'), + title: s__('LearnGitLab|Submit a merge request (MR)'), actionLabel: s__('LearnGitLab|Submit a merge request (MR)'), description: s__('LearnGitLab|Review and edit proposed changes to source code.'), + trackLabel: 'submit_a_merge_request_mr', section: 'plan', position: 1, }, - securityScanEnabled: { - title: s__('LearnGitLab|Run a Security scan using CI/CD'), - actionLabel: s__('LearnGitLab|Run a Security scan using CI/CD'), - description: s__('LearnGitLab|Scan your code to uncover vulnerabilities before deploying.'), - section: 'deploy', - position: 1, - }, issueCreated: { title: s__('LearnGitLab|Create an issue'), actionLabel: s__('LearnGitLab|Create an issue'), description: s__( 'LearnGitLab|Create/import issues (tickets) to collaborate on ideas and plan work.', ), + trackLabel: 'create_an_issue', section: 'plan', position: 0, }, + securityScanEnabled: { + title: s__('LearnGitLab|Run a Security scan using CI/CD'), + actionLabel: s__('LearnGitLab|Run a Security scan using CI/CD'), + description: s__('LearnGitLab|Scan your code to uncover vulnerabilities before deploying.'), + trackLabel: 'run_a_security_scan_using_ci_cd', + section: 'deploy', + position: 1, + }, + licenseScanningRun: { + title: s__('LearnGitLab|Scan dependencies for licenses'), + trackLabel: 'scan_dependencies_for_licenses', + trialRequired: true, + section: 'deploy', + position: 2, + }, + secureDependencyScanningRun: { + title: s__('LearnGitLab|Scan dependencies for vulnerabilities'), + trackLabel: 'scan_dependencies_for_vulnerabilities', + trialRequired: true, + section: 'deploy', + position: 3, + }, + secureDastRun: { + title: s__('LearnGitLab|Analyze your application for vulnerabilities with DAST'), + trackLabel: 'analyze_your_application_for_vulnerabilities_with_dast', + trialRequired: true, + section: 'deploy', + position: 4, + }, }; export const ACTION_SECTIONS = { diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_reports.vue b/app/assets/javascripts/pipelines/components/test_reports/test_reports.vue index 58d072b0005..3fb46a4f128 100644 --- a/app/assets/javascripts/pipelines/components/test_reports/test_reports.vue +++ b/app/assets/javascripts/pipelines/components/test_reports/test_reports.vue @@ -1,6 +1,7 @@ <script> import { GlLoadingIcon } from '@gitlab/ui'; import { mapActions, mapGetters, mapState } from 'vuex'; +import createTestReportsStore from '../../stores/test_reports'; import EmptyState from './empty_state.vue'; import TestSuiteTable from './test_suite_table.vue'; import TestSummary from './test_summary.vue'; @@ -15,9 +16,10 @@ export default { TestSummary, TestSummaryTable, }, + inject: ['blobPath', 'summaryEndpoint', 'suiteEndpoint'], computed: { - ...mapState(['isLoading', 'selectedSuiteIndex', 'testReports']), - ...mapGetters(['getSelectedSuite']), + ...mapState('testReports', ['isLoading', 'selectedSuiteIndex', 'testReports']), + ...mapGetters('testReports', ['getSelectedSuite']), showSuite() { return this.selectedSuiteIndex !== null; }, @@ -27,10 +29,19 @@ export default { }, }, created() { + this.$store.registerModule( + 'testReports', + createTestReportsStore({ + blobPath: this.blobPath, + summaryEndpoint: this.summaryEndpoint, + suiteEndpoint: this.suiteEndpoint, + }), + ); + this.fetchSummary(); }, methods: { - ...mapActions([ + ...mapActions('testReports', [ 'fetchTestSuite', 'fetchSummary', 'setSelectedSuiteIndex', diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue b/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue index 1e481d37017..1f438c63fee 100644 --- a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue +++ b/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue @@ -51,14 +51,18 @@ export default { }, }, computed: { - ...mapState(['pageInfo']), - ...mapGetters(['getSuiteTests', 'getSuiteTestCount', 'getSuiteArtifactsExpired']), + ...mapState('testReports', ['pageInfo']), + ...mapGetters('testReports', [ + 'getSuiteTests', + 'getSuiteTestCount', + 'getSuiteArtifactsExpired', + ]), hasSuites() { return this.getSuiteTests.length > 0; }, }, methods: { - ...mapActions(['setPage']), + ...mapActions('testReports', ['setPage']), }, wrapSymbols: ['::', '#', '.', '_', '-', '/', '\\'], i18n, diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue b/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue index 2b44ce57faa..8389c2a5104 100644 --- a/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue +++ b/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue @@ -19,7 +19,7 @@ export default { }, }, computed: { - ...mapGetters(['getTestSuites']), + ...mapGetters('testReports', ['getTestSuites']), hasSuites() { return this.getTestSuites.length > 0; }, diff --git a/app/assets/javascripts/pipelines/pipeline_test_details.js b/app/assets/javascripts/pipelines/pipeline_test_details.js index 27ab2418440..fe4ca8e9529 100644 --- a/app/assets/javascripts/pipelines/pipeline_test_details.js +++ b/app/assets/javascripts/pipelines/pipeline_test_details.js @@ -1,9 +1,10 @@ import Vue from 'vue'; +import Vuex from 'vuex'; import { parseBoolean } from '~/lib/utils/common_utils'; import Translate from '~/vue_shared/translate'; import TestReports from './components/test_reports/test_reports.vue'; -import createTestReportsStore from './stores/test_reports'; +Vue.use(Vuex); Vue.use(Translate); export const createTestDetails = (selector) => { @@ -16,11 +17,6 @@ export const createTestDetails = (selector) => { suiteEndpoint, artifactsExpiredImagePath, } = el?.dataset || {}; - const testReportsStore = createTestReportsStore({ - blobPath, - summaryEndpoint, - suiteEndpoint, - }); // eslint-disable-next-line no-new new Vue({ @@ -32,8 +28,11 @@ export const createTestDetails = (selector) => { emptyStateImagePath, artifactsExpiredImagePath, hasTestReport: parseBoolean(hasTestReport), + blobPath, + summaryEndpoint, + suiteEndpoint, }, - store: testReportsStore, + store: new Vuex.Store(), render(createElement) { return createElement('test-reports'); }, diff --git a/app/assets/javascripts/pipelines/stores/test_reports/index.js b/app/assets/javascripts/pipelines/stores/test_reports/index.js index 64d4b8bafb1..f45a53f47b7 100644 --- a/app/assets/javascripts/pipelines/stores/test_reports/index.js +++ b/app/assets/javascripts/pipelines/stores/test_reports/index.js @@ -1,16 +1,14 @@ -import Vue from 'vue'; -import Vuex from 'vuex'; import * as actions from './actions'; import * as getters from './getters'; import mutations from './mutations'; import state from './state'; -Vue.use(Vuex); - -export default (initialState) => - new Vuex.Store({ +export default (initialState) => { + return { + namespaced: true, actions, getters, mutations, state: state(initialState), - }); + }; +}; diff --git a/app/assets/javascripts/security_configuration/components/app.vue b/app/assets/javascripts/security_configuration/components/app.vue index 0e21d69310e..ecde9235e93 100644 --- a/app/assets/javascripts/security_configuration/components/app.vue +++ b/app/assets/javascripts/security_configuration/components/app.vue @@ -206,6 +206,7 @@ export default { <template #features> <feature-card v-for="feature in augmentedSecurityFeatures" + :id="feature.anchor" :key="feature.type" data-testid="security-testing-card" :feature="feature" diff --git a/app/assets/javascripts/security_configuration/components/constants.js b/app/assets/javascripts/security_configuration/components/constants.js index e4d2bd08f50..6efaf08a178 100644 --- a/app/assets/javascripts/security_configuration/components/constants.js +++ b/app/assets/javascripts/security_configuration/components/constants.js @@ -194,6 +194,7 @@ export const securityFeatures = [ helpPath: DAST_HELP_PATH, configurationHelpPath: DAST_CONFIG_HELP_PATH, type: REPORT_TYPE_DAST, + anchor: 'dast', }, { name: DEPENDENCY_SCANNING_NAME, @@ -201,6 +202,7 @@ export const securityFeatures = [ helpPath: DEPENDENCY_SCANNING_HELP_PATH, configurationHelpPath: DEPENDENCY_SCANNING_CONFIG_HELP_PATH, type: REPORT_TYPE_DEPENDENCY_SCANNING, + anchor: 'dependency-scanning', }, { name: CONTAINER_SCANNING_NAME, diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb index f425e996c2b..a996bad3fac 100644 --- a/app/controllers/oauth/applications_controller.rb +++ b/app/controllers/oauth/applications_controller.rb @@ -53,7 +53,9 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController def set_index_vars @applications = current_user.oauth_applications.load - @authorized_tokens = current_user.oauth_authorized_tokens.preload(:application).order(created_at: :desc).load # rubocop: disable CodeReuse/ActiveRecord + @authorized_tokens = current_user.oauth_authorized_tokens + .latest_per_application + .preload_application # Don't overwrite a value possibly set by `create` @application ||= Doorkeeper::Application.new diff --git a/app/experiments/security_actions_continuous_onboarding_experiment.rb b/app/experiments/security_actions_continuous_onboarding_experiment.rb new file mode 100644 index 00000000000..6adfbedc744 --- /dev/null +++ b/app/experiments/security_actions_continuous_onboarding_experiment.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class SecurityActionsContinuousOnboardingExperiment < ApplicationExperiment + def control_behavior + end + + def candidate_behavior + end +end diff --git a/app/helpers/integrations_helper.rb b/app/helpers/integrations_helper.rb index 8d5523464c7..a1512d40235 100644 --- a/app/helpers/integrations_helper.rb +++ b/app/helpers/integrations_helper.rb @@ -216,7 +216,7 @@ module IntegrationsHelper end def fields_for_integration(integration) - Integrations::FieldSerializer.new(integration: integration).represent(integration.global_fields).to_json + Integrations::FieldSerializer.new(integration: integration).represent(integration.form_fields).to_json end def integration_level(integration) diff --git a/app/helpers/learn_gitlab_helper.rb b/app/helpers/learn_gitlab_helper.rb index 890f7f099df..421cf84f98c 100644 --- a/app/helpers/learn_gitlab_helper.rb +++ b/app/helpers/learn_gitlab_helper.rb @@ -4,6 +4,7 @@ module LearnGitlabHelper IMAGE_PATH_PLAN = "learn_gitlab/section_plan.svg" IMAGE_PATH_DEPLOY = "learn_gitlab/section_deploy.svg" IMAGE_PATH_WORKSPACE = "learn_gitlab/section_workspace.svg" + LICENSE_SCANNING_RUN_URL = 'https://docs.gitlab.com/ee/user/compliance/license_compliance/index.html' def learn_gitlab_enabled?(project) return false unless current_user @@ -64,7 +65,7 @@ module LearnGitlabHelper git_write: project_path(project), merge_request_created: project_merge_requests_path(project), user_added: project_members_url(project), - security_scan_enabled: project_security_configuration_path(project) + **deploy_section_action_urls(project) ) end @@ -72,6 +73,23 @@ module LearnGitlabHelper LearnGitlab::Onboarding::ACTION_ISSUE_IDS.transform_values { |id| project_issue_url(learn_gitlab_project, id) } end + def deploy_section_action_urls(project) + experiment(:security_actions_continuous_onboarding, + namespace: project.namespace, + user: current_user, + sticky_to: current_user + ) do |e| + e.control { { security_scan_enabled: project_security_configuration_path(project) } } + e.candidate do + { + license_scanning_run: LICENSE_SCANNING_RUN_URL, + secure_dependency_scanning_run: project_security_configuration_path(project, anchor: 'dependency-scanning'), + secure_dast_run: project_security_configuration_path(project, anchor: 'dast') + } + end + end.run + end + def learn_gitlab_project @learn_gitlab_project ||= LearnGitlab::Project.new(current_user).project end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 18b6556039c..ced5fd31fd5 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -29,10 +29,6 @@ module Ci return_exit_code: -> (build) { build.exit_codes_defined? } }.freeze - DEFAULT_RETRIES = { - scheduler_failure: 2 - }.freeze - DEGRADATION_THRESHOLD_VARIABLE_NAME = 'DEGRADATION_THRESHOLD' RUNNERS_STATUS_CACHE_EXPIRATION = 1.minute diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index d7889407849..c48e21cf061 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -27,8 +27,6 @@ module Ci DEFAULT_CONFIG_PATH = CONFIG_EXTENSION CANCELABLE_STATUSES = (Ci::HasStatus::CANCELABLE_STATUSES + ['manual']).freeze - BridgeStatusError = Class.new(StandardError) - paginates_per 15 sha_attribute :source_sha diff --git a/app/models/integration.rb b/app/models/integration.rb index af8e8060d81..f5f701662e7 100644 --- a/app/models/integration.rb +++ b/app/models/integration.rb @@ -505,8 +505,8 @@ class Integration < ApplicationRecord fields.reject { _1[:type] == 'password' }.pluck(:name) end - def global_fields - fields + def form_fields + fields.reject { _1[:api_only] == true } end def configurable_events diff --git a/app/models/integrations/base_chat_notification.rb b/app/models/integrations/base_chat_notification.rb index 51f238d5eb9..c7992e4083c 100644 --- a/app/models/integrations/base_chat_notification.rb +++ b/app/models/integrations/base_chat_notification.rb @@ -139,8 +139,8 @@ module Integrations supported_events.map { |event| event_channel_name(event) } end - def global_fields - fields.reject { |field| field[:name].end_with?('channel') } + def form_fields + super.reject { |field| field[:name].end_with?('channel') } end def default_channel_placeholder diff --git a/app/models/integrations/jira.rb b/app/models/integrations/jira.rb index 125f52104d4..c9c9b9d59d6 100644 --- a/app/models/integrations/jira.rb +++ b/app/models/integrations/jira.rb @@ -71,11 +71,12 @@ module Integrations non_empty_password_help: -> { s_('JiraService|Leave blank to use your current password or API token.') }, help: -> { s_('JiraService|Use a password for server version and an API token for cloud version.') } + field :jira_issue_transition_id, api_only: true + # TODO: we can probably just delegate as part of # https://gitlab.com/gitlab-org/gitlab/issues/29404 # These fields are API only, so no field definition is required. data_field :jira_issue_transition_automatic - data_field :jira_issue_transition_id data_field :project_key data_field :issues_enabled data_field :vulnerabilities_enabled diff --git a/app/models/oauth_access_token.rb b/app/models/oauth_access_token.rb index 9789d8ed62b..20130f01d44 100644 --- a/app/models/oauth_access_token.rb +++ b/app/models/oauth_access_token.rb @@ -7,6 +7,8 @@ class OauthAccessToken < Doorkeeper::AccessToken alias_attribute :user, :resource_owner scope :distinct_resource_owner_counts, ->(applications) { where(application: applications).distinct.group(:application_id).count(:resource_owner_id) } + scope :latest_per_application, -> { select('distinct on(application_id) *').order(application_id: :desc, created_at: :desc) } + scope :preload_application, -> { preload(:application) } def scopes=(value) if value.is_a?(Array) diff --git a/app/models/user.rb b/app/models/user.rb index 20ff796aba0..2afd64358ef 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1626,7 +1626,7 @@ class User < ApplicationRecord end def oauth_authorized_tokens - Doorkeeper::AccessToken.where(resource_owner_id: id, revoked_at: nil) + OauthAccessToken.where(resource_owner_id: id, revoked_at: nil) end # Returns the projects a user contributed to in the last year. diff --git a/app/services/ci/external_pull_requests/create_pipeline_service.rb b/app/services/ci/external_pull_requests/create_pipeline_service.rb index 66127c94d35..ffc129eccda 100644 --- a/app/services/ci/external_pull_requests/create_pipeline_service.rb +++ b/app/services/ci/external_pull_requests/create_pipeline_service.rb @@ -10,24 +10,12 @@ module Ci return pull_request_not_open_error unless pull_request.open? return pull_request_branch_error unless pull_request.actual_branch_head? - create_pipeline_for(pull_request) - end - - private - - def create_pipeline_for(pull_request) Ci::ExternalPullRequests::CreatePipelineWorker.perform_async( project.id, current_user.id, pull_request.id ) end - def create_params(pull_request) - { - ref: pull_request.source_ref, - source_sha: pull_request.source_sha, - target_sha: pull_request.target_sha - } - end + private def pull_request_not_open_error ServiceResponse.error(message: 'The pull request is not opened', payload: nil) diff --git a/app/services/ci/job_artifacts/create_service.rb b/app/services/ci/job_artifacts/create_service.rb index 635111130d6..f658661a650 100644 --- a/app/services/ci/job_artifacts/create_service.rb +++ b/app/services/ci/job_artifacts/create_service.rb @@ -5,8 +5,6 @@ module Ci class CreateService < ::BaseService include Gitlab::Utils::UsageData - ArtifactsExistError = Class.new(StandardError) - LSIF_ARTIFACT_TYPE = 'lsif' METRICS_REPORT_UPLOAD_EVENT_NAME = 'i_testing_metrics_report_artifact_uploaders' @@ -74,10 +72,6 @@ module Ci Ci::JobArtifact.max_artifact_size(type: type, project: project) end - def forbidden_type_error(type) - error("#{type} artifacts are forbidden", :forbidden) - end - def too_large_error error('file size has reached maximum size limit', :payload_too_large) end |