From f23de8014c9104ab62c68e88b4c8e924469cd996 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 7 Jul 2023 06:08:10 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../components/pipeline_schedules_form.vue | 172 ++++++++++++---- .../update_pipeline_schedule.mutation.graphql | 6 + .../get_pipeline_schedules.query.graphql | 19 +- .../mount_pipeline_schedules_form_app.js | 4 - .../mutations/ci/pipeline_schedule/update.rb | 14 +- .../pipeline_schedule/variable_input_type.rb | 7 + app/helpers/ci/pipeline_schedules_helper.rb | 19 ++ .../pipeline_schedules/edit.html.haml | 3 +- .../projects/pipeline_schedules/new.html.haml | 2 +- .../backfill_missing_ci_cd_settings.yml | 6 + ...ay_state_allowlist_application_settings.rb | 11 ++ ...dd_relay_state_allowlist_saml_providers.rb | 11 ++ ...3_queue_backfill_missing_ci_cd_settings.rb | 25 +++ db/schema_migrations/20230628023103 | 1 + db/schema_migrations/20230703115902 | 1 + db/schema_migrations/20230703121859 | 1 + db/structure.sql | 4 +- doc/api/graphql/reference/index.md | 8 + doc/ci/index.md | 15 +- doc/ci/runners/runners_scope.md | 4 +- .../vulnerabilities/severities.md | 26 +++ .../backfill_missing_ci_cd_settings.rb | 39 ++++ locale/gitlab.pot | 12 +- .../pipeline_schedules_form_spec.js | 184 +++++++++++++++++- .../ci/pipeline_schedules/mock_data.js | 15 +- spec/frontend/fixtures/pipeline_schedules.rb | 6 + .../variable_input_type_spec.rb | 2 +- .../ci/pipeline_schedules_helper_spec.rb | 31 +++ .../backfill_missing_ci_cd_settings_spec.rb | 98 ++++++++++ ...ue_backfill_missing_ci_cd_settings_spec.rb | 26 +++ .../ci/pipeline_schedule_update_spec.rb | 42 +++- .../pipeline_schedules/update_service_spec.rb | 48 ++++- 32 files changed, 798 insertions(+), 64 deletions(-) create mode 100644 app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/update_pipeline_schedule.mutation.graphql create mode 100644 app/helpers/ci/pipeline_schedules_helper.rb create mode 100644 db/docs/batched_background_migrations/backfill_missing_ci_cd_settings.yml create mode 100644 db/migrate/20230703115902_add_relay_state_allowlist_application_settings.rb create mode 100644 db/migrate/20230703121859_add_relay_state_allowlist_saml_providers.rb create mode 100644 db/post_migrate/20230628023103_queue_backfill_missing_ci_cd_settings.rb create mode 100644 db/schema_migrations/20230628023103 create mode 100644 db/schema_migrations/20230703115902 create mode 100644 db/schema_migrations/20230703121859 create mode 100644 lib/gitlab/background_migration/backfill_missing_ci_cd_settings.rb create mode 100644 spec/helpers/ci/pipeline_schedules_helper_spec.rb create mode 100644 spec/lib/gitlab/background_migration/backfill_missing_ci_cd_settings_spec.rb create mode 100644 spec/migrations/20230628023103_queue_backfill_missing_ci_cd_settings_spec.rb diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue index 31500b919f3..d84a9a4a4b5 100644 --- a/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue +++ b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue @@ -8,17 +8,22 @@ import { GlFormGroup, GlFormInput, GlFormTextarea, + GlLoadingIcon, } from '@gitlab/ui'; import { __, s__ } from '~/locale'; import { createAlert } from '~/alert'; -import { visitUrl } from '~/lib/utils/url_utility'; +import { visitUrl, queryToObject } from '~/lib/utils/url_utility'; import { REF_TYPE_BRANCHES, REF_TYPE_TAGS } from '~/ref/constants'; import RefSelector from '~/ref/components/ref_selector.vue'; import TimezoneDropdown from '~/vue_shared/components/timezone_dropdown/timezone_dropdown.vue'; import IntervalPatternInput from '~/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue'; import createPipelineScheduleMutation from '../graphql/mutations/create_pipeline_schedule.mutation.graphql'; +import updatePipelineScheduleMutation from '../graphql/mutations/update_pipeline_schedule.mutation.graphql'; +import getPipelineSchedulesQuery from '../graphql/queries/get_pipeline_schedules.query.graphql'; import { VARIABLE_TYPE, FILE_TYPE } from '../constants'; +const scheduleId = queryToObject(window.location.search).id; + export default { components: { GlButton, @@ -29,20 +34,12 @@ export default { GlFormGroup, GlFormInput, GlFormTextarea, + GlLoadingIcon, RefSelector, TimezoneDropdown, IntervalPatternInput, }, - inject: [ - 'fullPath', - 'projectId', - 'defaultBranch', - 'cron', - 'cronTimezone', - 'dailyLimit', - 'settingsLink', - 'schedulesPath', - ], + inject: ['fullPath', 'projectId', 'defaultBranch', 'dailyLimit', 'settingsLink', 'schedulesPath'], props: { timezoneData: { type: Array, @@ -58,24 +55,74 @@ export default { required: true, }, }, + apollo: { + schedule: { + query: getPipelineSchedulesQuery, + variables() { + return { + projectPath: this.fullPath, + ids: scheduleId, + }; + }, + update(data) { + return data.project?.pipelineSchedules?.nodes[0] || {}; + }, + result({ data }) { + if (data) { + const { + project: { + pipelineSchedules: { nodes }, + }, + } = data; + + const schedule = nodes[0]; + const variables = schedule.variables?.nodes || []; + + this.description = schedule.description; + this.cron = schedule.cron; + this.cronTimezone = schedule.cronTimezone; + this.scheduleRef = schedule.ref; + this.variables = variables.map((variable) => { + return { + id: variable.id, + variableType: variable.variableType, + key: variable.key, + value: variable.value, + destroy: false, + }; + }); + this.addEmptyVariable(); + this.activated = schedule.active; + } + }, + skip() { + return !this.editing; + }, + error() { + createAlert({ message: this.$options.i18n.scheduleFetchError }); + }, + }, + }, data() { return { - cronValue: this.cron, + cron: '', description: '', scheduleRef: this.defaultBranch, activated: true, - timezone: this.cronTimezone, + cronTimezone: '', variables: [], + schedule: {}, }; }, i18n: { activated: __('Activated'), - cronTimezone: s__('PipelineSchedules|Cron timezone'), + cronTimezoneText: s__('PipelineSchedules|Cron timezone'), description: s__('PipelineSchedules|Description'), shortDescriptionPipeline: s__( 'PipelineSchedules|Provide a short description for this pipeline', ), - savePipelineSchedule: s__('PipelineSchedules|Save pipeline schedule'), + editScheduleBtnText: s__('PipelineSchedules|Edit pipeline schedule'), + createScheduleBtnText: s__('PipelineSchedules|Create pipeline schedule'), cancel: __('Cancel'), targetBranchTag: __('Select target branch or tag'), intervalPattern: s__('PipelineSchedules|Interval Pattern'), @@ -87,6 +134,12 @@ export default { scheduleCreateError: s__( 'PipelineSchedules|An error occurred while creating the pipeline schedule.', ), + scheduleUpdateError: s__( + 'PipelineSchedules|An error occurred while updating the pipeline schedule.', + ), + scheduleFetchError: s__( + 'PipelineSchedules|An error occurred while trying to fetch the pipeline schedule.', + ), }, typeOptions: { [VARIABLE_TYPE]: __('Variable'), @@ -114,9 +167,26 @@ export default { getEnabledRefTypes() { return [REF_TYPE_BRANCHES, REF_TYPE_TAGS]; }, - preparedVariables() { + preparedVariablesUpdate() { return this.variables.filter((variable) => variable.key !== ''); }, + preparedVariablesCreate() { + return this.preparedVariablesUpdate.map((variable) => { + return { + key: variable.key, + value: variable.value, + variableType: variable.variableType, + }; + }); + }, + loading() { + return this.$apollo.queries.schedule.loading; + }, + buttonText() { + return this.editing + ? this.$options.i18n.editScheduleBtnText + : this.$options.i18n.createScheduleBtnText; + }, }, created() { this.addEmptyVariable(); @@ -133,6 +203,7 @@ export default { variableType: VARIABLE_TYPE, key: '', value: '', + destroy: false, }); }, setVariableAttribute(key, attribute, value) { @@ -140,16 +211,11 @@ export default { variable[attribute] = value; }, removeVariable(index) { - this.variables.splice(index, 1); + this.variables[index].destroy = true; }, canRemove(index) { return index < this.variables.length - 1; }, - scheduleHandler() { - if (!this.editing) { - this.createPipelineSchedule(); - } - }, async createPipelineSchedule() { try { const { @@ -161,10 +227,10 @@ export default { variables: { input: { description: this.description, - cron: this.cronValue, - cronTimezone: this.timezone, + cron: this.cron, + cronTimezone: this.cronTimezone, ref: this.scheduleRef, - variables: this.preparedVariables, + variables: this.preparedVariablesCreate, active: this.activated, projectPath: this.fullPath, }, @@ -180,11 +246,48 @@ export default { createAlert({ message: this.$options.i18n.scheduleCreateError }); } }, + async updatePipelineSchedule() { + try { + const { + data: { + pipelineScheduleUpdate: { errors }, + }, + } = await this.$apollo.mutate({ + mutation: updatePipelineScheduleMutation, + variables: { + input: { + id: this.schedule.id, + description: this.description, + cron: this.cron, + cronTimezone: this.cronTimezone, + ref: this.scheduleRef, + variables: this.preparedVariablesUpdate, + active: this.activated, + }, + }, + }); + + if (errors.length > 0) { + createAlert({ message: errors[0] }); + } else { + visitUrl(this.schedulesPath); + } + } catch { + createAlert({ message: this.$options.i18n.scheduleUpdateError }); + } + }, + scheduleHandler() { + if (this.editing) { + this.updatePipelineSchedule(); + } else { + this.createPipelineSchedule(); + } + }, setCronValue(cron) { - this.cronValue = cron; + this.cron = cron; }, setTimezone(timezone) { - this.timezone = timezone.identifier || ''; + this.cronTimezone = timezone.identifier || ''; }, }, }; @@ -192,7 +295,8 @@ export default {