Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-02-27 15:09:55 +00:00
parent 12b96f0b82
commit 135b9a7019
67 changed files with 928 additions and 312 deletions

View File

@ -8,7 +8,6 @@ exclude:
- 'spec/**/*'
- 'ee/spec/**/*'
require:
- './haml_lint/linter/documentation_links.rb'
- './haml_lint/linter/inline_javascript.rb'
- './haml_lint/linter/no_plain_nodes.rb'

View File

@ -465,8 +465,6 @@ Gitlab/DocumentationLinks/HardcodedUrl:
Gitlab/DocumentationLinks/Link:
Enabled: true
Exclude:
- '**/*.haml'
GitlabSecurity/PublicSend:
Enabled: true

View File

@ -2279,11 +2279,11 @@ Gitlab/BoundedContexts:
- 'ee/app/graphql/mutations/iterations/create.rb'
- 'ee/app/graphql/mutations/iterations/delete.rb'
- 'ee/app/graphql/mutations/iterations/update.rb'
- 'ee/app/graphql/mutations/member_roles/base.rb'
- 'ee/app/graphql/mutations/member_roles/create.rb'
- 'ee/app/graphql/mutations/member_roles/admin/base.rb'
- 'ee/app/graphql/mutations/member_roles/admin/create.rb'
- 'ee/app/graphql/mutations/member_roles/admin/update.rb'
- 'ee/app/graphql/mutations/member_roles/base.rb'
- 'ee/app/graphql/mutations/member_roles/create.rb'
- 'ee/app/graphql/mutations/member_roles/delete.rb'
- 'ee/app/graphql/mutations/member_roles/update.rb'
- 'ee/app/graphql/mutations/quality_management/test_cases/create.rb'

View File

@ -320,7 +320,6 @@ Gitlab/StrongMemoizeAttr:
- 'ee/app/services/protected_environments/base_service.rb'
- 'ee/app/services/security/ingestion/tasks/ingest_vulnerabilities/mark_resolved_as_detected.rb'
- 'ee/app/services/security/report_summary_service.rb'
- 'ee/app/services/security/security_orchestration_policies/on_demand_scan_pipeline_configuration_service.rb'
- 'ee/app/services/security/security_orchestration_policies/operational_vulnerabilities_configuration_service.rb'
- 'ee/app/services/security/security_orchestration_policies/validate_policy_service.rb'
- 'ee/app/services/status_page/publish_attachments_service.rb'

View File

@ -20,7 +20,6 @@ Layout/EmptyLinesAroundMethodBody:
- 'lib/gitlab/database/partitioning/list/convert_table.rb'
- 'lib/gitlab/database/partitioning_migration_helpers/table_management_helpers.rb'
- 'lib/gitlab/diff/file.rb'
- 'lib/gitlab/fp/settings/default_settings_parser.rb'
- 'lib/gitlab/git/repository.rb'
- 'lib/gitlab/gitaly_client/operation_service.rb'
- 'lib/gitlab/import/import_failure_service.rb'
@ -28,5 +27,4 @@ Layout/EmptyLinesAroundMethodBody:
- 'spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb'
- 'spec/lib/gitlab/popen/runner_spec.rb'
- 'spec/support/helpers/workhorse_lfs_helpers.rb'
- 'spec/support/matchers/invoke_rop_steps.rb'
- 'tooling/lib/tooling/find_changes.rb'

View File

@ -261,7 +261,6 @@ Layout/LineEndStringConcatenationIndentation:
- 'ee/spec/requests/api/graphql/mutations/iterations/create_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/iterations/delete_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/iterations/update_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/member_role/create_member_role_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/projects/initialize_product_analytics_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/projects/product_analytics_project_settings_update_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/projects/set_compliance_framework_spec.rb'

View File

@ -727,7 +727,6 @@ Layout/LineLength:
- 'ee/app/services/security/report_summary_service.rb'
- 'ee/app/services/security/scanned_resources_counting_service.rb'
- 'ee/app/services/security/scanned_resources_service.rb'
- 'ee/app/services/security/security_orchestration_policies/on_demand_scan_pipeline_configuration_service.rb'
- 'ee/app/services/security/security_orchestration_policies/policy_commit_service.rb'
- 'ee/app/services/security/security_orchestration_policies/policy_configuration_validation_service.rb'
- 'ee/app/services/security/security_orchestration_policies/process_policy_service.rb'

View File

@ -33,7 +33,6 @@ Rails/InverseOf:
- 'app/models/merge_request/metrics.rb'
- 'app/models/namespace.rb'
- 'app/models/notification_setting.rb'
- 'app/models/packages/maven/metadatum.rb'
- 'app/models/project.rb'
- 'app/models/project_label.rb'
- 'app/models/resource_state_event.rb'

View File

@ -1110,7 +1110,6 @@ RSpec/BeEq:
- 'spec/models/integrations/jira_cloud_app_spec.rb'
- 'spec/models/integrations/jira_spec.rb'
- 'spec/models/integrations/prometheus_spec.rb'
- 'spec/models/integrations/telegram_spec.rb'
- 'spec/models/integrations/zentao_tracker_data_spec.rb'
- 'spec/models/issue_spec.rb'
- 'spec/models/jira_connect_installation_spec.rb'

View File

@ -330,7 +330,6 @@ RSpec/BeforeAllRoleAssignment:
- 'ee/spec/requests/api/graphql/boards/epic_lists_query_spec.rb'
- 'ee/spec/requests/api/graphql/ci/minutes/usage_spec.rb'
- 'ee/spec/requests/api/graphql/compliance_management/merge_requests/compliance_violations_spec.rb'
- 'ee/spec/requests/api/graphql/dora/dora_scores_spec.rb'
- 'ee/spec/requests/api/graphql/gitlab_subscriptions/preview_billable_user_change_spec.rb'
- 'ee/spec/requests/api/graphql/group/dast_profile_schedule_spec.rb'
- 'ee/spec/requests/api/graphql/group/epic/epic_aggregate_query_spec.rb'

View File

@ -574,7 +574,6 @@ RSpec/ContextWording:
- 'ee/spec/serializers/dashboard_operations_project_entity_spec.rb'
- 'ee/spec/serializers/ee/group_child_entity_spec.rb'
- 'ee/spec/serializers/ee/issue_sidebar_extras_entity_spec.rb'
- 'ee/spec/serializers/ee/merge_request_poll_cached_widget_entity_spec.rb'
- 'ee/spec/serializers/ee/user_serializer_spec.rb'
- 'ee/spec/serializers/environment_entity_spec.rb'
- 'ee/spec/serializers/issue_serializer_spec.rb'
@ -2203,7 +2202,6 @@ RSpec/ContextWording:
- 'spec/requests/api/project_clusters_spec.rb'
- 'spec/requests/api/project_container_repositories_spec.rb'
- 'spec/requests/api/project_events_spec.rb'
- 'spec/requests/api/project_export_spec.rb'
- 'spec/requests/api/project_packages_spec.rb'
- 'spec/requests/api/project_snippets_spec.rb'
- 'spec/requests/api/projects_spec.rb'

View File

@ -674,10 +674,7 @@ RSpec/FeatureCategory:
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/count_users_creating_ci_builds_metric_spec.rb'
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/count_users_deployment_approvals_spec.rb'
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/epics_deepest_relationship_level_metric_spec.rb'
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/historical_max_users_metrics_spec.rb'
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/license_management_jobs_metric_spec.rb'
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/license_metric_spec.rb'
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/licensee_metrics_spec.rb'
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/protected_environment_approval_rules_required_approvals_average_metric_spec.rb'
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/protected_environments_required_approvals_average_metric_spec.rb'
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/user_cap_setting_enabled_metric_spec.rb'
@ -902,7 +899,6 @@ RSpec/FeatureCategory:
- 'ee/spec/serializers/ee/issue_entity_spec.rb'
- 'ee/spec/serializers/ee/issue_sidebar_basic_entity_spec.rb'
- 'ee/spec/serializers/ee/issue_sidebar_extras_entity_spec.rb'
- 'ee/spec/serializers/ee/merge_request_poll_cached_widget_entity_spec.rb'
- 'ee/spec/serializers/ee/note_entity_spec.rb'
- 'ee/spec/serializers/ee/user_serializer_spec.rb'
- 'ee/spec/serializers/epic_entity_spec.rb'
@ -1727,7 +1723,6 @@ RSpec/FeatureCategory:
- 'spec/helpers/admin/identities_helper_spec.rb'
- 'spec/helpers/appearances_helper_spec.rb'
- 'spec/helpers/application_helper_spec.rb'
- 'spec/helpers/application_settings_helper_spec.rb'
- 'spec/helpers/auto_devops_helper_spec.rb'
- 'spec/helpers/award_emoji_helper_spec.rb'
- 'spec/helpers/badges_helper_spec.rb'
@ -2125,7 +2120,6 @@ RSpec/FeatureCategory:
- 'spec/lib/gitlab/ci/parsers/test/junit_spec.rb'
- 'spec/lib/gitlab/ci/parsers_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/build_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/command_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/create_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/ensure_environments_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/ensure_resource_groups_spec.rb'
@ -2502,7 +2496,6 @@ RSpec/FeatureCategory:
- 'spec/lib/gitlab/git/push_spec.rb'
- 'spec/lib/gitlab/git/raw_diff_change_spec.rb'
- 'spec/lib/gitlab/git/remote_mirror_spec.rb'
- 'spec/lib/gitlab/git/user_spec.rb'
- 'spec/lib/gitlab/git/util_spec.rb'
- 'spec/lib/gitlab/git/wiki_page_version_spec.rb'
- 'spec/lib/gitlab/git_access_design_spec.rb'
@ -3764,7 +3757,6 @@ RSpec/FeatureCategory:
- 'spec/serializers/member_user_entity_spec.rb'
- 'spec/serializers/merge_request_for_pipeline_entity_spec.rb'
- 'spec/serializers/merge_request_metrics_helper_spec.rb'
- 'spec/serializers/merge_request_poll_widget_entity_spec.rb'
- 'spec/serializers/merge_request_user_entity_spec.rb'
- 'spec/serializers/merge_request_widget_commit_entity_spec.rb'
- 'spec/serializers/merge_requests/pipeline_entity_spec.rb'

View File

@ -734,7 +734,6 @@ RSpec/NamedSubject:
- 'ee/spec/serializers/ee/issue_board_entity_spec.rb'
- 'ee/spec/serializers/ee/issue_entity_spec.rb'
- 'ee/spec/serializers/ee/issue_sidebar_extras_entity_spec.rb'
- 'ee/spec/serializers/ee/merge_request_poll_cached_widget_entity_spec.rb'
- 'ee/spec/serializers/ee/note_entity_spec.rb'
- 'ee/spec/serializers/environment_entity_spec.rb'
- 'ee/spec/serializers/epic_entity_spec.rb'
@ -2459,7 +2458,6 @@ RSpec/NamedSubject:
- 'spec/models/integrations/jenkins_spec.rb'
- 'spec/models/integrations/matrix_spec.rb'
- 'spec/models/integrations/squash_tm_spec.rb'
- 'spec/models/integrations/telegram_spec.rb'
- 'spec/models/integrations/zentao_spec.rb'
- 'spec/models/internal_id_spec.rb'
- 'spec/models/issue/metrics_spec.rb'

View File

@ -72,7 +72,6 @@ RSpec/SubjectDeclaration:
- 'spec/models/event_collection_spec.rb'
- 'spec/models/group_spec.rb'
- 'spec/models/integrations/matrix_spec.rb'
- 'spec/models/integrations/telegram_spec.rb'
- 'spec/models/issue_spec.rb'
- 'spec/models/project_spec.rb'
- 'spec/models/x509_certificate_spec.rb'

View File

@ -3,7 +3,6 @@
RSpec/VerifiedDoubleReference:
Exclude:
- 'ee/spec/controllers/groups/analytics/productivity_analytics_controller_spec.rb'
- 'ee/spec/controllers/groups/security/policies_controller_spec.rb'
- 'ee/spec/features/custom_models/code_suggestions_spec.rb'
- 'ee/spec/features/custom_models/duo_chat_spec.rb'
- 'ee/spec/features/merge_request/user_sees_security_policy_rules_licence_compliance_spec.rb'
@ -49,7 +48,6 @@ RSpec/VerifiedDoubleReference:
- 'ee/spec/requests/api/graphql/project/google_cloud/artifact_registry/docker_images_spec.rb'
- 'ee/spec/requests/api/graphql/user_code_suggestions_available_spec.rb'
- 'ee/spec/requests/api/security_scans_spec.rb'
- 'ee/spec/requests/projects/security/policies_controller_spec.rb'
- 'ee/spec/serializers/dashboard_environments_project_entity_spec.rb'
- 'ee/spec/serializers/vulnerabilities/finding_entity_spec.rb'
- 'ee/spec/services/analytics/cycle_analytics/consistency_check_service_spec.rb'

View File

@ -86,7 +86,6 @@ Style/GuardClause:
- 'app/models/operations/feature_flags/strategy.rb'
- 'app/models/operations/feature_flags/user_list.rb'
- 'app/models/packages/conan/file_metadatum.rb'
- 'app/models/packages/maven/metadatum.rb'
- 'app/models/pages_domain.rb'
- 'app/models/personal_access_token.rb'
- 'app/models/project.rb'
@ -161,7 +160,6 @@ Style/GuardClause:
- 'app/services/protected_branches/legacy_api_update_service.rb'
- 'app/services/repositories/changelog_service.rb'
- 'app/services/snippets/repository_validation_service.rb'
- 'app/services/todo_service.rb'
- 'app/services/users/build_service.rb'
- 'app/services/wikis/create_attachment_service.rb'
- 'app/uploaders/content_type_whitelist.rb'

View File

@ -47,7 +47,6 @@ Style/IfUnlessModifier:
- 'app/models/packages/conan/file_metadatum.rb'
- 'app/models/packages/dependency.rb'
- 'app/models/packages/go/module.rb'
- 'app/models/packages/maven/metadatum.rb'
- 'app/models/pages_domain.rb'
- 'app/models/project.rb'
- 'app/models/project_team.rb'
@ -317,7 +316,6 @@ Style/IfUnlessModifier:
- 'ee/app/services/merge_trains/refresh_merge_request_service.rb'
- 'ee/app/services/projects/mark_for_deletion_service.rb'
- 'ee/app/services/projects/update_mirror_service.rb'
- 'ee/app/services/security/security_orchestration_policies/on_demand_scan_pipeline_configuration_service.rb'
- 'ee/app/services/security/security_orchestration_policies/policy_configuration_validation_service.rb'
- 'ee/app/services/security/security_orchestration_policies/process_policy_service.rb'
- 'ee/app/services/security/security_orchestration_policies/project_create_service.rb'

View File

@ -1228,7 +1228,6 @@ Style/InlineDisableAnnotation:
- 'ee/app/services/app_sec/dast/site_tokens/find_or_create_service.rb'
- 'ee/app/services/app_sec/dast/sites/find_or_create_service.rb'
- 'ee/app/services/approval_rules/params_filtering_service.rb'
- 'ee/app/services/billable_members/destroy_service.rb'
- 'ee/app/services/ci/minutes/additional_packs/create_service.rb'
- 'ee/app/services/ci/minutes/refresh_cached_data_service.rb'
- 'ee/app/services/ci/minutes/reset_usage_service.rb'

View File

@ -35,7 +35,6 @@ Style/SuperArguments:
- 'app/models/current.rb'
- 'app/models/hooks/service_hook.rb'
- 'app/models/integrations/matrix.rb'
- 'app/models/integrations/telegram.rb'
- 'app/models/issue.rb'
- 'app/models/label.rb'
- 'app/models/list.rb'

View File

@ -55,5 +55,5 @@ export default {
};
</script>
<template>
<ci-icon v-if="status" :status="statusObject" show-status-text class="!gl-border-0" />
<ci-icon v-if="status" :status="statusObject" show-status-text />
</template>

View File

@ -0,0 +1,10 @@
mutation updatePipelineVariablesDefaultRoleGroupSetting(
$fullPath: ID!
$pipelineVariablesDefaultRole: PipelineVariablesDefaultRoleType!
) {
namespaceSettingsUpdate(
input: { fullPath: $fullPath, pipelineVariablesDefaultRole: $pipelineVariablesDefaultRole }
) {
errors
}
}

View File

@ -0,0 +1,8 @@
query getPipelineVariablesDefaultRoleGroupSetting($fullPath: ID!) {
group(fullPath: $fullPath) {
id
ciCdSettings {
pipelineVariablesDefaultRole
}
}
}

View File

@ -0,0 +1,32 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import PipelineVariablesDefaultRole from './pipeline_variables_default_role.vue';
Vue.use(VueApollo);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
export default (containerId = 'js-pipeline-variables-default-role') => {
const containerEl = document.getElementById(containerId);
if (!containerEl) {
return false;
}
const { fullPath } = containerEl.dataset;
return new Vue({
el: containerEl,
name: 'PipelineVariablesDefaultRoleRoot',
apolloProvider,
provide: {
fullPath,
},
render(createElement) {
return createElement(PipelineVariablesDefaultRole);
},
});
};

View File

@ -0,0 +1,135 @@
<script>
import { GlButton, GlFormGroup, GlFormRadio, GlFormRadioGroup, GlLink } from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import { createAlert } from '~/alert';
import { __, s__ } from '~/locale';
import { reportToSentry } from '~/ci/utils';
import getPipelineVariablesDefaultRoleSetting from './graphql/queries/get_pipeline_variables_default_role_group_setting.query.graphql';
import updatePipelineVariablesDefaultRoleSetting from './graphql/mutations/update_pipeline_variables_default_role_group_setting.mutation.graphql';
export const DEFAULT_ROLE_DEVELOPER = 'DEVELOPER';
export const DEFAULT_ROLE_MAINTAINER = 'MAINTAINER';
export const DEFAULT_ROLE_NO_ONE = 'NO_ONE_ALLOWED';
export const DEFAULT_ROLE_OWNER = 'OWNER';
export default {
name: 'PipelineVariablesDefaultRole',
helpPath: helpPagePath('ci/variables/_index', {
anchor: 'cicd-variable-precedence',
}),
ROLE_OPTIONS: [
{
text: __('No one allowed'),
value: DEFAULT_ROLE_NO_ONE,
help: s__('CiVariables|Pipeline variables cannot be used.'),
},
{
text: __('Owner'),
value: DEFAULT_ROLE_OWNER,
},
{
text: __('Maintainer'),
value: DEFAULT_ROLE_MAINTAINER,
},
{
text: __('Developer'),
value: DEFAULT_ROLE_DEVELOPER,
},
],
components: { GlButton, GlFormGroup, GlFormRadio, GlFormRadioGroup, GlLink },
inject: ['fullPath'],
data() {
return {
isSubmitting: false,
pipelineVariablesDefaultRole: null,
};
},
apollo: {
pipelineVariablesDefaultRole: {
query: getPipelineVariablesDefaultRoleSetting,
variables() {
return {
fullPath: this.fullPath,
};
},
update({ group }) {
return (
group?.ciCdSettings?.pipelineVariablesDefaultRole?.toUpperCase() || DEFAULT_ROLE_NO_ONE
);
},
error(err) {
createAlert({
message: s__(
'CiVariables|There was a problem fetching the pipeline variables default role.',
),
});
reportToSentry(this.$options.name, err);
},
},
},
methods: {
async updateDefaultRole() {
this.isSubmitting = true;
try {
const {
data: {
namespaceSettingsUpdate: { errors },
},
} = await this.$apollo.mutate({
mutation: updatePipelineVariablesDefaultRoleSetting,
variables: {
fullPath: this.fullPath,
pipelineVariablesDefaultRole: this.pipelineVariablesDefaultRole,
},
});
if (errors.length) {
createAlert({ message: errors[0].message });
reportToSentry(this.$options.name, errors[0].message);
} else {
this.$toast.show(s__('CiVariables|Pipeline variable access role successfully updated.'));
}
} catch (err) {
createAlert({
message: s__(
'CiVariables|There was a problem updating the pipeline variables default role setting.',
),
});
reportToSentry(this.$options.name, err);
}
this.isSubmitting = false;
},
},
};
</script>
<template>
<div class="gl-mb-5">
<gl-form-group :label="s__('CiVariables|Default role to use pipeline variables')">
<template #label-description>
<span>{{
s__(
'CiVariables|SSelect the default minimum role to use in new projects, to run a new pipeline with pipeline variables.',
)
}}</span>
<gl-link :href="$options.helpPath" target="_blank">{{
s__('CiVariables|What are pipeline variables?')
}}</gl-link>
</template>
<gl-form-radio-group v-model="pipelineVariablesDefaultRole">
<gl-form-radio v-for="role in $options.ROLE_OPTIONS" :key="role.value" :value="role.value">
{{ role.text }}
<template v-if="role.help" #help>{{ role.help }}</template>
</gl-form-radio>
</gl-form-radio-group>
<gl-button
category="primary"
variant="confirm"
class="gl-mt-3"
:loading="isSubmitting"
@click="updateDefaultRole"
>{{ __('Save changes') }}
</gl-button>
</gl-form-group>
</div>
</template>

View File

@ -2,6 +2,7 @@ import initStaleRunnerCleanupSetting from 'ee_else_ce/group_settings/stale_runne
import { initAllowRunnerRegistrationTokenToggle } from '~/group_settings/allow_runner_registration_token_toggle';
import { initJwtCiCdJobTokenEnabledToggle } from '~/group_settings/jwt_ci_cd_job_token_enabled_toggle';
import initPipelineVariablesDefaultRole from '~/group_settings/pipeline_variables_default_role';
import initVariableList from '~/ci/ci_variable_list';
import initSharedRunnersForm from '~/group_settings/mount_shared_runners';
import initSettingsPanels from '~/settings_panels';
@ -15,3 +16,4 @@ initJwtCiCdJobTokenEnabledToggle();
initSharedRunnersForm();
initStaleRunnerCleanupSetting();
initVariableList();
initPipelineVariablesDefaultRole();

View File

@ -40,14 +40,21 @@ module Mutations
required: false,
description: 'Variables for the pipeline.'
argument :inputs, [Types::Ci::Inputs::InputType],
required: false,
description: 'Inputs for the pipeline.',
experiment: { milestone: '17.10' }
authorize :create_pipeline
def resolve(project_path:, ref:, async: false, variables: {})
def resolve(project_path:, ref:, async: false, variables: {}, inputs: [])
project = authorized_find!(project_path)
creation_params = { ref: ref, variables_attributes: variables.map(&:to_h) }
service = ::Ci::CreatePipelineService.new(project, current_user, creation_params)
response = execute_service(service, source, async)
execute_options = EXECUTE_OPTIONS.merge(inputs: parse_inputs(inputs))
service = ::Ci::CreatePipelineService.new(project, current_user, creation_params)
response = execute_service(service, source, async, execute_options)
if response.success?
if async
@ -62,11 +69,11 @@ module Mutations
private
def execute_service(service, source, async)
def execute_service(service, source, async, options)
if async
service.execute_async(source, EXECUTE_OPTIONS)
service.execute_async(source, options)
else
service.execute(source, **EXECUTE_OPTIONS)
service.execute(source, **options)
end
end
@ -75,6 +82,10 @@ module Mutations
'api'
end
def parse_inputs(inputs)
inputs.to_h { |input| [input.key, input.value] }
end
end
end
end

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
module Types
module Ci
module Inputs
class InputType < BaseInputObject
graphql_name 'CiInputsInputType'
description 'Attributes for defining an input.'
argument :key,
GraphQL::Types::String,
required: true,
description: 'Name of the input.'
argument :value,
Inputs::ValueInputType,
required: true,
description: 'Value of the input.'
end
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
module Types
module Ci
module Inputs
class ValueInputType < BaseScalar
graphql_name 'CiInputsValueInputType'
description 'Value for a CI input. Can be a string, array, number, or boolean.'
def self.coerce_input(value, _ctx)
case value
when String, Array, Numeric, TrueClass, FalseClass, NilClass
value
else
raise GraphQL::CoercionError, 'Invalid CI input value'
end
end
end
end
end
end

View File

@ -13,3 +13,5 @@ module Types
end
end
end
::Types::PermissionTypes::WorkItem.prepend_mod

View File

@ -87,7 +87,7 @@ module WebHooks
end
def help_path
'user/project/integrations/webhooks'
Gitlab::Routing.url_helpers.help_page_path('user/project/integrations/webhooks.md')
end
# @return [Boolean] Whether or not the WebHook is currently throttled.

View File

@ -31,7 +31,7 @@ class SystemHook < WebHook
end
def help_path
'administration/system_hooks'
Gitlab::Routing.url_helpers.help_page_path('administration/system_hooks.md')
end
override :validate_public_url?

View File

@ -1,6 +1,10 @@
- save_endpoint = local_assigns.fetch(:save_endpoint, nil)
- is_group = !@group.nil?
- is_project = !@project.nil?
- is_root_group = @group && @group.root?
- if is_root_group
#js-pipeline-variables-default-role{ data: { full_path: @group.full_path } }
- if is_project
#js-ci-variables-minimum-override-role-app{ data: { full_path: @project.full_path } }

View File

@ -10,14 +10,14 @@
window.gl.mrWidgetData.pipeline_etag = '#{graphql_etag_pipeline_sha_path(@merge_request.diff_head_sha)}';
window.gl.mrWidgetData.squash_before_merge_help_path = '#{help_page_path("user/project/merge_requests/squash_and_merge.md")}';
window.gl.mrWidgetData.ci_troubleshooting_docs_path = '#{help_page_path('ci/debugging.md')}';
window.gl.mrWidgetData.mr_troubleshooting_docs_path = '#{help_page_path('user/project/merge_requests/reviews/_index.md', anchor: 'troubleshooting')}';
window.gl.mrWidgetData.pipeline_must_succeed_docs_path = '#{help_page_path('user/project/merge_requests/merge_when_pipeline_succeeds.md', anchor: 'require-a-successful-pipeline-for-merge')}';
window.gl.mrWidgetData.mr_troubleshooting_docs_path = '#{help_page_path('user/project/merge_requests/merge_request_troubleshooting.md')}';
window.gl.mrWidgetData.pipeline_must_succeed_docs_path = '#{help_page_path('user/project/merge_requests/auto_merge.md', anchor: 'require-a-successful-pipeline-for-merge')}';
window.gl.mrWidgetData.code_coverage_check_help_page_path = '#{help_page_path('ci/testing/code_coverage/_index.md', anchor: 'add-a-coverage-check-approval-rule')}';
window.gl.mrWidgetData.security_configuration_path = '#{project_security_configuration_path(@project)}';
window.gl.mrWidgetData.license_compliance_docs_path = '#{help_page_path('user/compliance/license_scanning_of_cyclonedx_files/_index.md')}';
window.gl.mrWidgetData.eligible_approvers_docs_path = '#{help_page_path('user/project/merge_requests/approvals/rules.md', anchor: 'eligible-approvers')}';
window.gl.mrWidgetData.approvals_help_path = '#{help_page_path("user/project/merge_requests/approvals/_index.md")}';
window.gl.mrWidgetData.codequality_help_path = '#{help_page_path("ci/testing/code_quality.md", anchor: "code-quality-reports")}';
window.gl.mrWidgetData.codequality_help_path = '#{help_page_path("ci/testing/code_quality.md", anchor: "pipeline-details-view")}';
window.gl.mrWidgetData.false_positive_doc_url = '#{help_page_path('user/application_security/vulnerabilities/_index.md')}';
window.gl.mrWidgetData.can_view_false_positive = '#{@merge_request.project.licensed_feature_available?(:sast_fp_reduction).to_s}';
window.gl.mrWidgetData.user_preferences_gitpod_path = '#{profile_preferences_path(anchor: 'user_gitpod_enabled')}';

View File

@ -1,4 +1,4 @@
- webhooks_link = tag_pair(link_to('', help_page_path(hook.help_path), target: '_blank', rel: 'noopener noreferrer'), :webhooks_link_start, :webhooks_link_end)
- webhooks_link = tag_pair(link_to('', hook.help_path, target: '_blank', rel: 'noopener noreferrer'), :webhooks_link_start, :webhooks_link_end)
- if @project
- integrations_link = tag_pair(link_to('', scoped_integrations_path(project: @project)), :integrations_link_start, :integrations_link_end)

View File

@ -0,0 +1,13 @@
---
table_name: work_item_current_statuses
classes:
- WorkItems::Statuses::CurrentStatus
feature_categories:
- team_planning
description: Persists link between work item and a system defined or custom status
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/181962
milestone: '17.10'
gitlab_schema: gitlab_main_cell
sharding_key:
namespace_id: namespaces
table_size: unknown

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
class TruncateSecurityPipelineExecutionProjectSchedules < Gitlab::Database::Migration[2.2]
milestone '17.10'
disable_ddl_transaction!
def up
truncate_tables!('security_pipeline_execution_project_schedules')
end
def down
# no-op
end
end

View File

@ -0,0 +1,32 @@
# frozen_string_literal: true
class AddCronAndTimeWindowSecondsToSecurityPipelineExecutionProjectSchedules < Gitlab::Database::Migration[2.2]
milestone '17.10'
disable_ddl_transaction!
TABLE_NAME = :security_pipeline_execution_project_schedules
def up
with_lock_retries do
# rubocop:disable Rails/NotNullColumn -- table was emptied by previous migration
add_column TABLE_NAME, :time_window_seconds, :integer, null: false, if_not_exists: true
add_column TABLE_NAME, :cron, :text, null: false, if_not_exists: true
add_column TABLE_NAME, :cron_timezone, :text, null: false, if_not_exists: true
# rubocop:enable Rails/NotNullColumn
end
add_text_limit TABLE_NAME, :cron, 128
add_text_limit TABLE_NAME, :cron_timezone, 255
constraint_name = check_constraint_name(TABLE_NAME, :time_window_seconds, "positive")
add_check_constraint TABLE_NAME, "time_window_seconds > 0", constraint_name
end
def down
with_lock_retries do
remove_column TABLE_NAME, :time_window_seconds, if_exists: true
remove_column TABLE_NAME, :cron, if_exists: true
remove_column TABLE_NAME, :cron_timezone, if_exists: true
end
end
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class RemoveUniqueIndexOnPipelineExecutionSchedulesProjectsAndPolicies < Gitlab::Database::Migration[2.2]
milestone '17.10'
disable_ddl_transaction!
TABLE_NAME = :security_pipeline_execution_project_schedules
INDEX_NAME = "uniq_idx_pipeline_execution_schedules_projects_and_policies"
def up
remove_index(TABLE_NAME, name: INDEX_NAME) # rubocop:disable Migration/RemoveIndex -- table was truncated
end
def down
# rubocop:disable Migration/AddIndex -- table was truncated
add_index(TABLE_NAME, %w[project_id security_policy_id], unique: true, name: INDEX_NAME)
# rubocop:enable Migration/AddIndex
end
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class AddIndexOnPipelineExecutionSchedulesProjects < Gitlab::Database::Migration[2.2]
milestone '17.9'
disable_ddl_transaction!
TABLE_NAME = :security_pipeline_execution_project_schedules
INDEX_NAME = 'idx_pipeline_execution_schedules_on_project_id'
def up
# rubocop:disable Migration/AddIndex -- table was truncated
add_index(TABLE_NAME, :project_id, name: INDEX_NAME)
# rubocop:enable Migration/AddIndex
end
def down
remove_index(TABLE_NAME, name: INDEX_NAME) # rubocop:disable Migration/RemoveIndex -- table was truncated
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
class CreateWorkItemCurrentStatuses < Gitlab::Database::Migration[2.2]
milestone '17.10'
def change
# factory is in `ee/spec/factories/work_items/statuses/current_status.rb`
create_table :work_item_current_statuses do |t| # rubocop:disable Migration/EnsureFactoryForTable -- reason above
t.references :namespace, null: false, foreign_key: { on_delete: :cascade }
t.references :work_item, null: false, foreign_key: { to_table: :issues, on_delete: :cascade },
index: { unique: true }
t.bigint :system_defined_status_id, null: true
# Should be references if model already existed, but we'll add this in a follow up MR.
# We can already add it here so column order is correct.
t.bigint :custom_status_id, null: true
t.datetime_with_timezone :updated_at, null: false
t.index [:work_item_id, :system_defined_status_id],
name: 'idx_wi_current_statuses_on_wi_id_system_def_status_id_unique', unique: true
t.index [:work_item_id, :custom_status_id],
name: 'idx_wi_current_statuses_on_wi_id_custom_status_id_unique', unique: true
end
end
end

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
class AddCheckConstraintToWorkItemCurrentStatuses < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.10'
def up
# Ensure that either system_defined_status_id or custom_status_id is not null
# but allow both ids to be set.
add_multi_column_not_null_constraint(
:work_item_current_statuses, :system_defined_status_id, :custom_status_id, limit: 0, operator: '>'
)
end
def down
remove_multi_column_not_null_constraint(:work_item_current_statuses, :system_defined_status_id, :custom_status_id)
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
class AddWorkItemCurrentStatusesNamespaceIdTrigger < Gitlab::Database::Migration[2.2]
milestone '17.10'
def up
install_sharding_key_assignment_trigger(
table: :work_item_current_statuses,
sharding_key: :namespace_id,
parent_table: :issues,
parent_sharding_key: :namespace_id,
foreign_key: :work_item_id
)
end
def down
remove_sharding_key_assignment_trigger(
table: :work_item_current_statuses,
sharding_key: :namespace_id,
parent_table: :issues,
parent_sharding_key: :namespace_id,
foreign_key: :work_item_id
)
end
end

View File

@ -0,0 +1 @@
63d3440161336ed8d556565a0c7add785ba47324f3dae6c21d89d6c34277c91d

View File

@ -0,0 +1 @@
73a8cecec58922c7b289c71e83d4217c7084d000e59c36ae98fb5cab8bda38c1

View File

@ -0,0 +1 @@
b9d0f1433e900711b3811ff97e17f0e33b6f688f0ec6bdfec5adfdb8f32b83a1

View File

@ -0,0 +1 @@
5c65a79dae8281c14503682c9e2147fa624893a6f22d6f64e12d4d8c5d2ca2bf

View File

@ -0,0 +1 @@
2ec2eba7b8a6680e26cf9e925bb62fdc46948b3a29020dc8402d5d85897ebe6f

View File

@ -0,0 +1 @@
a0f415b0088543960d7e50b58ea8f4d50c1b1102f75a6a5bd35e9f730c03bb33

View File

@ -0,0 +1 @@
48660f996820dd8220fa23dbd68ebea9e45aa960a68e8ce2607d3c9fb6fd9e80

View File

@ -2022,6 +2022,22 @@ RETURN NEW;
END
$$;
CREATE FUNCTION trigger_4fc14aa830b1() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF NEW."namespace_id" IS NULL THEN
SELECT "namespace_id"
INTO NEW."namespace_id"
FROM "issues"
WHERE "issues"."id" = NEW."work_item_id";
END IF;
RETURN NEW;
END
$$;
CREATE FUNCTION trigger_54707c384ad7() RETURNS trigger
LANGUAGE plpgsql
AS $$
@ -21298,7 +21314,13 @@ CREATE TABLE security_pipeline_execution_project_schedules (
updated_at timestamp with time zone NOT NULL,
next_run_at timestamp with time zone NOT NULL,
security_policy_id bigint NOT NULL,
project_id bigint NOT NULL
project_id bigint NOT NULL,
time_window_seconds integer NOT NULL,
cron text NOT NULL,
cron_timezone text NOT NULL,
CONSTRAINT check_b93315bfbb CHECK ((char_length(cron_timezone) <= 255)),
CONSTRAINT check_bbbe4b1b8d CHECK ((char_length(cron) <= 128)),
CONSTRAINT check_c440017377 CHECK ((time_window_seconds > 0))
);
CREATE SEQUENCE security_pipeline_execution_project_schedules_id_seq
@ -23962,6 +23984,25 @@ CREATE TABLE work_item_colors (
CONSTRAINT check_485e19ad7b CHECK ((char_length(color) <= 7))
);
CREATE TABLE work_item_current_statuses (
id bigint NOT NULL,
namespace_id bigint NOT NULL,
work_item_id bigint NOT NULL,
system_defined_status_id bigint,
custom_status_id bigint,
updated_at timestamp with time zone NOT NULL,
CONSTRAINT check_0734284d2c CHECK ((num_nonnulls(custom_status_id, system_defined_status_id) > 0))
);
CREATE SEQUENCE work_item_current_statuses_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE work_item_current_statuses_id_seq OWNED BY work_item_current_statuses.id;
CREATE TABLE work_item_dates_sources (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
@ -26284,6 +26325,8 @@ ALTER TABLE ONLY wiki_page_slugs ALTER COLUMN id SET DEFAULT nextval('wiki_page_
ALTER TABLE ONLY wiki_repository_states ALTER COLUMN id SET DEFAULT nextval('wiki_repository_states_id_seq'::regclass);
ALTER TABLE ONLY work_item_current_statuses ALTER COLUMN id SET DEFAULT nextval('work_item_current_statuses_id_seq'::regclass);
ALTER TABLE ONLY work_item_hierarchy_restrictions ALTER COLUMN id SET DEFAULT nextval('work_item_hierarchy_restrictions_id_seq'::regclass);
ALTER TABLE ONLY work_item_number_field_values ALTER COLUMN id SET DEFAULT nextval('work_item_number_field_values_id_seq'::regclass);
@ -29341,6 +29384,9 @@ ALTER TABLE ONLY wiki_repository_states
ALTER TABLE ONLY work_item_colors
ADD CONSTRAINT work_item_colors_pkey PRIMARY KEY (issue_id);
ALTER TABLE ONLY work_item_current_statuses
ADD CONSTRAINT work_item_current_statuses_pkey PRIMARY KEY (id);
ALTER TABLE ONLY work_item_dates_sources
ADD CONSTRAINT work_item_dates_sources_pkey PRIMARY KEY (issue_id);
@ -31202,6 +31248,8 @@ CREATE INDEX idx_pat_last_used_ips_on_pat_id ON personal_access_token_last_used_
CREATE INDEX idx_personal_access_tokens_on_previous_personal_access_token_id ON personal_access_tokens USING btree (previous_personal_access_token_id);
CREATE INDEX idx_pipeline_execution_schedules_on_project_id ON security_pipeline_execution_project_schedules USING btree (project_id);
CREATE INDEX idx_pipeline_execution_schedules_security_policy_id_and_id ON security_pipeline_execution_project_schedules USING btree (security_policy_id, id);
CREATE INDEX idx_pkgs_conan_file_metadata_on_pkg_file_id_when_recipe_file ON packages_conan_file_metadata USING btree (package_file_id) WHERE (conan_file_type = 1);
@ -31354,6 +31402,10 @@ CREATE INDEX idx_vulnerability_reads_project_id_scanner_id_vulnerability_id ON v
CREATE INDEX idx_vulnerability_statistics_on_traversal_ids_and_letter_grade ON vulnerability_statistics USING btree (traversal_ids, letter_grade) WHERE (archived = false);
CREATE UNIQUE INDEX idx_wi_current_statuses_on_wi_id_custom_status_id_unique ON work_item_current_statuses USING btree (work_item_id, custom_status_id);
CREATE UNIQUE INDEX idx_wi_current_statuses_on_wi_id_system_def_status_id_unique ON work_item_current_statuses USING btree (work_item_id, system_defined_status_id);
CREATE UNIQUE INDEX idx_wi_number_values_on_work_item_id_custom_field_id ON work_item_number_field_values USING btree (work_item_id, custom_field_id);
CREATE INDEX idx_wi_select_field_values_on_custom_field_select_option_id ON work_item_select_field_values USING btree (custom_field_select_option_id);
@ -35748,6 +35800,10 @@ CREATE INDEX index_wiki_repository_states_on_verification_state ON wiki_reposito
CREATE INDEX index_wiki_repository_states_pending_verification ON wiki_repository_states USING btree (verified_at NULLS FIRST) WHERE (verification_state = 0);
CREATE INDEX index_work_item_current_statuses_on_namespace_id ON work_item_current_statuses USING btree (namespace_id);
CREATE UNIQUE INDEX index_work_item_current_statuses_on_work_item_id ON work_item_current_statuses USING btree (work_item_id);
CREATE INDEX index_work_item_hierarchy_restrictions_on_child_type_id ON work_item_hierarchy_restrictions USING btree (child_type_id);
CREATE UNIQUE INDEX index_work_item_hierarchy_restrictions_on_parent_and_child ON work_item_hierarchy_restrictions USING btree (parent_type_id, child_type_id);
@ -36122,8 +36178,6 @@ CREATE UNIQUE INDEX uniq_idx_on_packages_conan_package_revisions_revision ON pac
CREATE UNIQUE INDEX uniq_idx_packages_packages_on_project_id_name_version_ml_model ON packages_packages USING btree (project_id, name, version) WHERE ((package_type = 14) AND (status <> 4));
CREATE UNIQUE INDEX uniq_idx_pipeline_execution_schedules_projects_and_policies ON security_pipeline_execution_project_schedules USING btree (project_id, security_policy_id);
CREATE UNIQUE INDEX uniq_idx_project_compliance_framework_on_project_framework ON project_compliance_framework_settings USING btree (project_id, framework_id);
CREATE UNIQUE INDEX uniq_idx_security_policy_requirements_on_requirement_and_policy ON security_policy_requirements USING btree (compliance_framework_security_policy_id, compliance_requirement_id);
@ -38392,6 +38446,8 @@ CREATE TRIGGER trigger_4cc5c3ac4d7f BEFORE INSERT OR UPDATE ON bulk_import_expor
CREATE TRIGGER trigger_4dc8ec48e038 BEFORE INSERT OR UPDATE ON requirements_management_test_reports FOR EACH ROW EXECUTE FUNCTION trigger_4dc8ec48e038();
CREATE TRIGGER trigger_4fc14aa830b1 BEFORE INSERT OR UPDATE ON work_item_current_statuses FOR EACH ROW EXECUTE FUNCTION trigger_4fc14aa830b1();
CREATE TRIGGER trigger_54707c384ad7 BEFORE INSERT OR UPDATE ON security_orchestration_policy_rule_schedules FOR EACH ROW EXECUTE FUNCTION trigger_54707c384ad7();
CREATE TRIGGER trigger_56d49f4ed623 BEFORE INSERT OR UPDATE ON workspace_variables FOR EACH ROW EXECUTE FUNCTION trigger_56d49f4ed623();
@ -42348,6 +42404,9 @@ ALTER TABLE ONLY design_management_repository_states
ALTER TABLE ONLY web_hooks
ADD CONSTRAINT fk_rails_d35697648e FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY work_item_current_statuses
ADD CONSTRAINT fk_rails_d37e56a437 FOREIGN KEY (work_item_id) REFERENCES issues(id) ON DELETE CASCADE;
ALTER TABLE ONLY group_group_links
ADD CONSTRAINT fk_rails_d3a0488427 FOREIGN KEY (shared_group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@ -42549,6 +42608,9 @@ ALTER TABLE ONLY iterations_cadences
ALTER TABLE ONLY dast_profiles
ADD CONSTRAINT fk_rails_ed1e66fbbf FOREIGN KEY (dast_site_profile_id) REFERENCES dast_site_profiles(id) ON DELETE CASCADE;
ALTER TABLE ONLY work_item_current_statuses
ADD CONSTRAINT fk_rails_ed36c2df68 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY project_security_settings
ADD CONSTRAINT fk_rails_ed4abe1338 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;

View File

@ -55,6 +55,9 @@ You can use the following GitLab Duo Chat features with GitLab Duo Self-Hosted:
- [Ask about GitLab](../../user/gitlab_duo_chat/examples.md#ask-about-gitlab)
- [Ask about a specific issue](../../user/gitlab_duo_chat/examples.md#ask-about-a-specific-issue)
- [Ask about a specific epic](../../user/gitlab_duo_chat/examples.md#ask-about-a-specific-epic)
- [Ask about a specific merge request](../../user/gitlab_duo_chat/examples.md#ask-about-a-specific-merge-request)
- [Ask about a specific commit](../../user/gitlab_duo_chat/examples.md#ask-about-a-specific-commit)
- [Ask about a specific pipeline job](../../user/gitlab_duo_chat/examples.md#ask-about-a-specific-pipeline-job)
- [Explain selected code](../../user/gitlab_duo_chat/examples.md#explain-selected-code)
- [Ask about or generate code](../../user/gitlab_duo_chat/examples.md#ask-about-or-generate-code)
- [Ask follow up questions](../../user/gitlab_duo_chat/examples.md#ask-follow-up-questions)
@ -64,7 +67,7 @@ You can use the following GitLab Duo Chat features with GitLab Duo Self-Hosted:
- [Fix code in the IDE](../../user/gitlab_duo_chat/examples.md#fix-code-in-the-ide)
- [Write tests in the IDE](../../user/gitlab_duo_chat/examples.md#write-tests-in-the-ide)
- [Ask about CI/CD](../../user/gitlab_duo_chat/examples.md#ask-about-cicd)
- [Use universal and IDE slash commands](../../user/gitlab_duo_chat/examples.md#gitlab-duo-chat-slash-commands)
- [Use IDE slash commands](../../user/gitlab_duo_chat/examples.md#ide)
### Prerequisites

View File

@ -8703,6 +8703,7 @@ Input type: `PipelineCreateInput`
| ---- | ---- | ----------- |
| <a id="mutationpipelinecreateasync"></a>`async` {{< icon name="warning-solid" >}} | [`Boolean`](#boolean) | **Deprecated:** **Status**: Experiment. Introduced in GitLab 17.8. |
| <a id="mutationpipelinecreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationpipelinecreateinputs"></a>`inputs` {{< icon name="warning-solid" >}} | [`[CiInputsInputType!]`](#ciinputsinputtype) | **Deprecated:** **Status**: Experiment. Introduced in GitLab 17.10. |
| <a id="mutationpipelinecreateprojectpath"></a>`projectPath` | [`ID!`](#id) | Full path of the project that is triggering the pipeline. |
| <a id="mutationpipelinecreateref"></a>`ref` | [`String!`](#string) | Ref on which to run the pipeline. |
| <a id="mutationpipelinecreatevariables"></a>`variables` | [`[CiVariableInput!]`](#civariableinput) | Variables for the pipeline. |
@ -39523,6 +39524,7 @@ Check permissions for the current user on a work item.
| <a id="workitempermissionsadminparentlink"></a>`adminParentLink` | [`Boolean!`](#boolean) | If `true`, the user can perform `admin_parent_link` on this resource. |
| <a id="workitempermissionsadminworkitem"></a>`adminWorkItem` | [`Boolean!`](#boolean) | If `true`, the user can perform `admin_work_item` on this resource. |
| <a id="workitempermissionsadminworkitemlink"></a>`adminWorkItemLink` | [`Boolean!`](#boolean) | If `true`, the user can perform `admin_work_item_link` on this resource. |
| <a id="workitempermissionsblockedworkitems"></a>`blockedWorkItems` | [`Boolean`](#boolean) | If `true`, the user can perform `blocked_work_items` on the work item. |
| <a id="workitempermissionscloneworkitem"></a>`cloneWorkItem` | [`Boolean!`](#boolean) | If `true`, the user can perform `clone_work_item` on this resource. |
| <a id="workitempermissionscreatenote"></a>`createNote` | [`Boolean!`](#boolean) | If `true`, the user can perform `create_note` on this resource. |
| <a id="workitempermissionsdeleteworkitem"></a>`deleteWorkItem` | [`Boolean!`](#boolean) | If `true`, the user can perform `delete_work_item` on this resource. |
@ -44298,6 +44300,10 @@ A `CiCatalogResourcesVersionID` is a global ID. It is encoded as a string.
An example `CiCatalogResourcesVersionID` is: `"gid://gitlab/Ci::Catalog::Resources::Version/1"`.
### `CiInputsValueInputType`
Value for a CI input. Can be a string, array, number, or boolean.
### `CiJobArtifactID`
A `CiJobArtifactID` is a global ID. It is encoded as a string.
@ -46630,6 +46636,17 @@ Field that are available while modifying the custom mapping attributes for an HT
| <a id="branchprotectioninputmergeaccesslevels"></a>`mergeAccessLevels` | [`[MergeAccessLevelInput!]`](#mergeaccesslevelinput) | Details about who can merge into the branch rule target. |
| <a id="branchprotectioninputpushaccesslevels"></a>`pushAccessLevels` | [`[PushAccessLevelInput!]`](#pushaccesslevelinput) | Details about who can push to the branch rule target. |
### `CiInputsInputType`
Attributes for defining an input.
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="ciinputsinputtypekey"></a>`key` | [`String!`](#string) | Name of the input. |
| <a id="ciinputsinputtypevalue"></a>`value` | [`CiInputsValueInputType!`](#ciinputsvalueinputtype) | Value of the input. |
### `CiVariableInput`
Attributes for defining a CI/CD variable.

View File

@ -32,10 +32,10 @@ module ActiveRecord
def belongs_to_fixed_items(association_name, fixed_items_class:, foreign_key: nil)
foreign_key ||= "#{association_name}_id"
raise "Missing attribute #{foreign_key}" unless attribute_names.include?(foreign_key)
# Getter method
define_method(association_name) do
raise "Missing attribute #{foreign_key}" unless attribute_names.include?(foreign_key)
current_id = read_attribute(foreign_key)
return if current_id.nil?
@ -53,12 +53,16 @@ module ActiveRecord
# Setter method
define_method(:"#{association_name}=") do |static_object|
raise "Missing attribute #{foreign_key}" unless attribute_names.include?(foreign_key)
@cached_static_associations&.delete(association_name)
write_attribute(foreign_key, static_object&.id)
end
# Query method
define_method(:"#{association_name}?") do
raise "Missing attribute #{foreign_key}" unless attribute_names.include?(foreign_key)
attribute_present?(foreign_key)
end

View File

@ -56,19 +56,35 @@ RSpec.describe ActiveRecord::FixedItemsModel::HasOne, feature_category: :shared
it { is_expected.to respond_to(:static_item?) }
context 'when foreign key attribute does not exist' do
it 'raises runtime error' do
before do
stub_const('TestRecord', Class.new do
include ActiveModel::Attributes
include ActiveRecord::FixedItemsModel::HasOne
attribute :static_item_id, :integer
# No need for mock methods because they're not called
# because of the guard raise
belongs_to_fixed_items :doesnt_exist, fixed_items_class: TestStaticModel
end)
end
it 'getter raises runtime error' do
expect do
stub_const('TestRecord', Class.new do
include ActiveModel::Attributes
include ActiveRecord::FixedItemsModel::HasOne
record.doesnt_exist
end.to raise_error(RuntimeError, "Missing attribute doesnt_exist_id")
end
attribute :static_item_id, :integer
it 'setter raises runtime error' do
expect do
record.doesnt_exist = nil
end.to raise_error(RuntimeError, "Missing attribute doesnt_exist_id")
end
# No need for mock methods because they're not called
# because of the guard raise
belongs_to_fixed_items :doesnt_exist, fixed_items_class: TestStaticModel
end)
it 'query method raises runtime error' do
expect do
record.doesnt_exist?
end.to raise_error(RuntimeError, "Missing attribute doesnt_exist_id")
end
end

View File

@ -1,118 +0,0 @@
# frozen_string_literal: true
require_relative '../../lib/gitlab/utils/markdown'
module HamlLint
class Linter
# This class is responsible for detection of help_page_path helpers
# with incorrect links or anchors
class DocumentationLinks < Linter
include ::HamlLint::LinterRegistry
include ::Gitlab::Utils::Markdown
extend ::RuboCop::AST::NodePattern::Macros
DOCS_DIRECTORY = File.join(File.expand_path('../..', __dir__), 'doc')
def_node_matcher :help_link, <<~PATTERN
(send _ {:help_page_url :help_page_path} $...)
PATTERN
MARKDOWN_HEADER = %r{\A\#{1,6}\s+(?<header>.+)\Z}
def visit_script(node)
check(node)
end
def visit_silent_script(node)
check(node)
end
def visit_tag(node)
check(node)
end
private
def check(node)
ast_tree = fetch_ast_tree(node)
return unless ast_tree
ast_tree.descendants.each do |child_node|
match = extract_link_and_anchor(child_node)
validate_node(node, match)
end
end
def validate_node(node, match)
return if match.empty?
link = match[:link]
path_to_file = detect_path_to_file(link)
unless File.file?(path_to_file)
record_lint(node, "help_page_path points to the unknown location: #{path_to_file}")
return
end
unless correct_anchor?(path_to_file, match[:anchor])
record_lint(node, "anchor (#{match[:anchor]}) is missing in: #{path_to_file}")
end
record_lint(node, "add .md extension to the link: #{link}") unless link.end_with?('.md')
end
def extract_link_and_anchor(ast_tree)
link_match, attributes_match = help_link(ast_tree)
{ link: fetch_link(link_match), anchor: fetch_anchor(attributes_match) }.compact
end
def fetch_ast_tree(node)
# Sometimes links are provided via data attributes in html tag
return node.parsed_attributes.syntax_tree if node.type == :tag
parse_script(node).syntax_tree
end
def parse_script(node)
# It's a workaround for cases for scripts ending with "do"
# For some reason they don't parse correctly
code = node.script.delete_suffix(' do')
HamlLint::ParsedRuby.new(HamlLint::RubyParser.new.parse(code))
end
def detect_path_to_file(link)
path = File.join(DOCS_DIRECTORY, link)
path += '.md' unless path.end_with?('.md')
path
end
def fetch_link(link_match)
return unless link_match && link_match.str_type?
link_match.value
end
def fetch_anchor(attributes_match)
return unless attributes_match
attributes_match.each_pair do |pkey, pvalue|
break pvalue.value if pkey.value == :anchor
end
end
def correct_anchor?(path_to_file, anchor)
return true unless anchor
File.open(path_to_file).any? do |line|
result = line.match(MARKDOWN_HEADER)
string_to_anchor(result[:header]) == anchor if result
end
end
end
end
end

View File

@ -155,7 +155,7 @@ gitlab-enrich-cdx-results:
GLAS_STATIC_REACHABILITY_MATCHER_VERSION: "v1.0.1"
GLAS_REPORT: $GITLAB_ADVANCED_SAST_SCA_FILENAME
SCA_TO_SARIF_PROJECT_ID: 60962090
DEPENDENCY_SCANNING_PATTERN: "**/gl-sbom-*.cdx.json"
DEPENDENCY_SCANNING_PATTERN: "**/gl-sbom-*-*.cdx.json"
image:
name: "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG"
entrypoint: [""]

View File

@ -12463,6 +12463,9 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
msgid "CiVariables|Default role to use pipeline variables"
msgstr ""
msgid "CiVariables|Delete variable"
msgstr ""
@ -12529,6 +12532,9 @@ msgstr ""
msgid "CiVariables|No matching values"
msgstr ""
msgid "CiVariables|Pipeline variable access role successfully updated."
msgstr ""
msgid "CiVariables|Pipeline variable minimum override role successfully updated."
msgstr ""
@ -12553,6 +12559,9 @@ msgstr ""
msgid "CiVariables|Run job again"
msgstr ""
msgid "CiVariables|SSelect the default minimum role to use in new projects, to run a new pipeline with pipeline variables."
msgstr ""
msgid "CiVariables|Scope"
msgstr ""
@ -12589,6 +12598,12 @@ msgstr ""
msgid "CiVariables|The value must have %{charsAmount} characters."
msgstr ""
msgid "CiVariables|There was a problem fetching the pipeline variables default role."
msgstr ""
msgid "CiVariables|There was a problem updating the pipeline variables default role setting."
msgstr ""
msgid "CiVariables|There was an error fetching the inherited CI variables."
msgstr ""
@ -50816,9 +50831,6 @@ msgstr ""
msgid "ScanResultPolicy|All licenses have been selected"
msgstr ""
msgid "ScanResultPolicy|Allow except on"
msgstr ""
msgid "ScanResultPolicy|Allow the merge request to proceed, even if not all criteria are met"
msgstr ""
@ -50864,9 +50876,6 @@ msgstr ""
msgid "ScanResultPolicy|Denied license"
msgstr ""
msgid "ScanResultPolicy|Deny except on"
msgstr ""
msgid "ScanResultPolicy|Don't show me this again"
msgstr ""
@ -50885,6 +50894,9 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
msgid "ScanResultPolicy|Exceptions that require approval"
msgstr ""
msgid "ScanResultPolicy|Fail closed"
msgstr ""
@ -51050,6 +51062,9 @@ msgstr ""
msgid "ScanResultPolicy|Severity is:"
msgstr ""
msgid "ScanResultPolicy|Specify the packages where this license requires approval before use"
msgstr ""
msgid "ScanResultPolicy|Status is:"
msgstr ""
@ -51059,9 +51074,6 @@ msgstr ""
msgid "ScanResultPolicy|Unknown"
msgstr ""
msgid "ScanResultPolicy|Use purl format for package paths: %{schemaStart}scheme:type/namespace/name@version?qualifiers#subpath%{schemaEnd}. For multiple packages, separate paths with comma \",\"."
msgstr ""
msgid "ScanResultPolicy|When %{scanType} %{scanners} runs against the %{branches} %{branchExceptions} and find(s) %{vulnerabilitiesNumber} %{boldDescription} of the following criteria:"
msgstr ""
@ -52173,9 +52185,6 @@ msgstr ""
msgid "SecurityOrchestration|All types"
msgstr ""
msgid "SecurityOrchestration|Allow except on these packages"
msgstr ""
msgid "SecurityOrchestration|Allowed licenses"
msgstr ""
@ -52314,9 +52323,6 @@ msgstr ""
msgid "SecurityOrchestration|Denied licenses"
msgstr ""
msgid "SecurityOrchestration|Deny except on these packages"
msgstr ""
msgid "SecurityOrchestration|Denylist details"
msgstr ""
@ -52928,6 +52934,9 @@ msgstr ""
msgid "SecurityOrchestration|Use default mode for scoping"
msgstr ""
msgid "SecurityOrchestration|Use the format %{schemaStart}path-to-package@package-version%{schemaEnd}. For multiple packages, separate paths with commas. For example: path/file1.yaml@1.1.1, path/file2.yaml@2.2.2"
msgstr ""
msgid "SecurityOrchestration|Users can skip pipelines"
msgstr ""

View File

@ -202,12 +202,6 @@ tests = [
expected: ['spec/lib/release_highlights/validator_spec.rb']
},
{
explanation: 'The documentation index page is used in this haml_lint spec',
changed_file: 'doc/_index.md',
expected: ['spec/haml_lint/linter/documentation_links_spec.rb']
},
{
explanation: 'Spec for FOSS model',
changed_file: 'app/models/uploads/base.rb',

View File

@ -256,7 +256,11 @@ RSpec.describe 'Database schema',
system_access_group_microsoft_graph_access_tokens: %w[temp_source_id], # temporary column that is not a foreign key
system_access_group_microsoft_applications: %w[temp_source_id], # temporary column that is not a foreign key
subscription_user_add_on_assignment_versions: %w[item_id user_id purchase_id], # Managed by paper_trail gem, no need for FK on the historical data
virtual_registries_packages_maven_cache_entries: %w[group_id] # We can't use a foreign key due to object storage references
virtual_registries_packages_maven_cache_entries: %w[group_id], # We can't use a foreign key due to object storage references
# system_defined_status_id reference to fixed items model which is stored in code
# custom_status_id to be implemented association, column exists for better column ordering
# TODO: Remove custom_status_id https://gitlab.com/gitlab-org/gitlab/-/work_items/520312
work_item_current_statuses: %w[system_defined_status_id custom_status_id]
}.with_indifferent_access.freeze
end

View File

@ -0,0 +1,200 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { shallowMount } from '@vue/test-utils';
import { GlButton, GlFormGroup, GlFormRadio, GlFormRadioGroup } from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import { createAlert } from '~/alert';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import PipelineVariablesDefaultRole, {
DEFAULT_ROLE_MAINTAINER,
DEFAULT_ROLE_NO_ONE,
} from '~/group_settings/pipeline_variables_default_role/pipeline_variables_default_role.vue';
import updatePipelineVariablesDefaultRoleSetting from '~/group_settings/pipeline_variables_default_role/graphql/mutations/update_pipeline_variables_default_role_group_setting.mutation.graphql';
import getPipelineVariablesDefaultRoleSetting from '~/group_settings/pipeline_variables_default_role/graphql/queries/get_pipeline_variables_default_role_group_setting.query.graphql';
Vue.use(VueApollo);
jest.mock('~/alert');
const $toast = {
show: jest.fn(),
};
const TEST_FULL_PATH = 'group/project';
describe('PipelineVariablesDefaultRole', () => {
let wrapper;
const defaultQueryResponse = jest.fn().mockResolvedValue({
data: {
group: {
id: '1',
ciCdSettings: {
pipelineVariablesDefaultRole: 'developer',
},
},
},
});
const defaultMutationResponse = jest.fn().mockResolvedValue({
data: {
namespaceSettingsUpdate: {
errors: [],
},
},
});
const createComponent = async ({
queryHandler = defaultQueryResponse,
mutationHandler = defaultMutationResponse,
} = {}) => {
const apolloProvider = createMockApollo([
[getPipelineVariablesDefaultRoleSetting, queryHandler],
[updatePipelineVariablesDefaultRoleSetting, mutationHandler],
]);
wrapper = shallowMount(PipelineVariablesDefaultRole, {
provide: {
fullPath: TEST_FULL_PATH,
},
mocks: {
$toast,
},
apolloProvider,
});
await waitForPromises();
};
const findFormGroup = () => wrapper.findComponent(GlFormGroup);
const findRadioGroup = () => wrapper.findComponent(GlFormRadioGroup);
const findRadioButtons = () => wrapper.findAllComponents(GlFormRadio);
const findSaveButton = () => wrapper.findComponent(GlButton);
const selectRadioOption = async (value, index) => {
findRadioGroup().vm.$emit('input', value);
findRadioButtons().at(index).vm.$emit('change');
await waitForPromises();
};
afterEach(() => {
jest.clearAllMocks();
});
describe('on render', () => {
it('renders the form group with correct label', async () => {
await createComponent();
expect(findFormGroup().exists()).toBe(true);
expect(findFormGroup().attributes('label')).toBe('Default role to use pipeline variables');
});
it('renders all role options as radio buttons', async () => {
await createComponent();
expect(findRadioButtons()).toHaveLength(PipelineVariablesDefaultRole.ROLE_OPTIONS.length);
PipelineVariablesDefaultRole.ROLE_OPTIONS.forEach((option, index) => {
expect(findRadioButtons().at(index).attributes('value')).toBe(option.value);
expect(findRadioButtons().at(index).text()).toContain(option.text);
});
});
it('has the correct help path', () => {
expect(PipelineVariablesDefaultRole.helpPath).toBe(
helpPagePath('ci/variables/_index', {
anchor: 'cicd-variable-precedence',
}),
);
});
});
describe('GraphQL operations', () => {
describe('query', () => {
it('fetches initial role setting successfully', async () => {
await createComponent();
expect(defaultQueryResponse).toHaveBeenCalledWith({ fullPath: TEST_FULL_PATH });
expect(findRadioButtons().at(3).attributes('value')).toBe('DEVELOPER');
expect(wrapper.vm.pipelineVariablesDefaultRole).toBe('DEVELOPER');
});
it('sets default role to NO_ONE_ALLOWED when query returns null', async () => {
const queryHandler = jest.fn().mockResolvedValue({
data: {
group: null,
},
});
await createComponent({ queryHandler });
expect(wrapper.vm.pipelineVariablesDefaultRole).toBe(DEFAULT_ROLE_NO_ONE);
});
it('shows error alert when query fails', async () => {
const queryHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
await createComponent({ queryHandler });
expect(createAlert).toHaveBeenCalledWith({
message: 'There was a problem fetching the pipeline variables default role.',
});
});
});
describe('mutation', () => {
it('updates role setting successfully', async () => {
await createComponent();
await selectRadioOption(DEFAULT_ROLE_MAINTAINER, 2);
findSaveButton().vm.$emit('click');
expect(defaultMutationResponse).toHaveBeenCalledWith({
fullPath: TEST_FULL_PATH,
pipelineVariablesDefaultRole: DEFAULT_ROLE_MAINTAINER,
});
});
it('displays a toast message on success', async () => {
await createComponent();
await selectRadioOption(DEFAULT_ROLE_MAINTAINER, 2);
findSaveButton().vm.$emit('click');
await waitForPromises();
expect($toast.show).toHaveBeenCalledWith(
'Pipeline variable access role successfully updated.',
);
});
it('shows error alert when mutation returns errors', async () => {
const mutationHandler = jest.fn().mockResolvedValue({
data: {
namespaceSettingsUpdate: {
errors: [{ message: 'Update failed' }],
},
},
});
await createComponent({ mutationHandler });
await selectRadioOption(DEFAULT_ROLE_MAINTAINER, 2);
findSaveButton().vm.$emit('click');
await waitForPromises();
expect(createAlert).toHaveBeenCalledWith({
message: 'Update failed',
});
});
it('shows error alert when mutation fails', async () => {
const mutationHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
await createComponent({ mutationHandler });
await selectRadioOption(DEFAULT_ROLE_MAINTAINER, 2);
findSaveButton().vm.$emit('click');
await waitForPromises();
expect(createAlert).toHaveBeenCalledWith({
message: 'There was a problem updating the pipeline variables default role setting.',
});
});
});
});
});

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['CiInputsInputType'], feature_category: :pipeline_composition do
specify { expect(described_class.graphql_name).to eq('CiInputsInputType') }
it 'has the correct arguments' do
expect(described_class.arguments.keys).to match_array(%w[key value])
end
end

View File

@ -0,0 +1,34 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['CiInputsValueInputType'], feature_category: :pipeline_composition do
specify { expect(described_class.graphql_name).to eq('CiInputsValueInputType') }
describe '.coerce_input' do
subject(:coerce_input) { described_class.coerce_isolated_input(value) }
context 'on valid values' do
using RSpec::Parameterized::TableSyntax
where(:value, :result) do
'foo' | 'foo'
1 | 1
[1, 2] | [1, 2]
true | true
false | false
nil | nil
end
with_them do
it { is_expected.to eq(result) }
end
end
context 'on invalid values' do
let(:value) { { foo: :bar } }
it { expect { coerce_input }.to raise_error(GraphQL::CoercionError) }
end
end
end

View File

@ -1,102 +0,0 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'haml_lint'
require 'haml_lint/spec'
require_relative '../../../haml_lint/linter/documentation_links'
RSpec.describe HamlLint::Linter::DocumentationLinks, feature_category: :tooling do
include_context 'linter'
shared_examples 'link validation rules' do |link_pattern|
context 'when link_to points to the existing file path' do
let(:haml) { "= link_to 'Description', #{link_pattern}('_index.md')" }
it { is_expected.not_to report_lint }
end
context 'when link_to points to the existing file with valid anchor' do
let(:haml) { "= link_to 'Description', #{link_pattern}('_index.md', anchor: 'user-accounts'), target: '_blank'" }
it { is_expected.not_to report_lint }
end
context 'when link_to points to the existing file path without .md extension' do
let(:haml) { "= link_to 'Description', #{link_pattern}('index')" }
it { is_expected.to report_lint }
end
context 'when anchor is not correct' do
let(:haml) { "= link_to 'Description', #{link_pattern}('_index.md', anchor: 'wrong')" }
it { is_expected.to report_lint }
context "when #{link_pattern} has multiple options" do
let(:haml) { "= link_to 'Description', #{link_pattern}('_index.md', key: :value, anchor: 'wrong')" }
it { is_expected.to report_lint }
end
end
context 'when file path is wrong' do
let(:haml) { "= link_to 'Description', #{link_pattern}('wrong.md'), target: '_blank'" }
it { is_expected.to report_lint }
context 'when haml ends with block definition' do
let(:haml) { "= link_to 'Description', #{link_pattern}('wrong.md') do" }
it { is_expected.to report_lint }
end
end
context 'when link with wrong file path is assigned to a variable' do
let(:haml) { "- my_link = link_to 'Description', #{link_pattern}('wrong.md')" }
it { is_expected.to report_lint }
end
context 'when it is a broken code' do
let(:haml) { "= I am broken! ]]]]" }
it { is_expected.not_to report_lint }
end
context 'when anchor belongs to a different element' do
let(:haml) { "= link_to 'Description', #{link_pattern}('_index.md'), target: (anchor: 'blank')" }
it { is_expected.not_to report_lint }
end
context "when a simple #{link_pattern}" do
let(:haml) { "- url = #{link_pattern}('wrong')" }
it { is_expected.to report_lint }
end
context 'when link is not a string' do
let(:haml) { "- url = #{link_pattern}(help_url)" }
it { is_expected.not_to report_lint }
end
context 'when link is a part of the tag' do
let(:haml) { ".data-form{ data: { url: #{link_pattern}('wrong') } }" }
it { is_expected.to report_lint }
end
context 'when the second link is invalid' do
let(:haml) { ".data-form{ data: { url: #{link_pattern}('_index.md'), wrong_url: #{link_pattern}('wrong') } }" }
it { is_expected.to report_lint }
end
end
it_behaves_like 'link validation rules', 'help_page_path'
it_behaves_like 'link validation rules', 'help_page_url'
it_behaves_like 'link validation rules', 'Rails.application.routes.url_helpers.help_page_url'
it_behaves_like 'link validation rules', 'Gitlab::Routing.url_helpers.help_page_url'
end

View File

@ -251,6 +251,6 @@ RSpec.describe SystemHook, feature_category: :webhooks do
describe '#help_path' do
subject { build(:system_hook).help_path }
it { is_expected.to eq('administration/system_hooks') }
it { is_expected.to eq('/help/administration/system_hooks.md') }
end
end

View File

@ -72,6 +72,105 @@ RSpec.describe 'PipelineCreate', feature_category: :pipeline_composition do
expect(created_pipeline.source).to eq('api')
expect(mutation_response['pipeline']['id']).to eq(created_pipeline.to_global_id.to_s)
end
context 'when passing inputs' do
let(:inputs) do
[
{ key: 'deploy_strategy', value: 'blue-green' },
{ key: 'job_stage', value: 'deploy' },
{ key: 'test_script', value: ['echo "test"'] },
{ key: 'test_rules', value: [{ if: '$CI_PIPELINE_SOURCE == "api"' }] }, # static source of the mutation
{ key: 'test_framework', value: '$TEST_FRAMEWORK' }
]
end
let(:params) { { ref: 'master', inputs: inputs } }
before do
stub_ci_pipeline_yaml_file(
File.read(Rails.root.join('spec/lib/gitlab/ci/config/yaml/fixtures/complex-included-ci.yml'))
)
end
it 'creates a pipeline using the inputs' do
expect do
post_graphql_mutation(mutation, current_user: user)
end.to change { ::Ci::Pipeline.count }.by(1)
created_pipeline = ::Ci::Pipeline.last
expect(created_pipeline.builds.map(&:name)).to contain_exactly(
'my-job-build 1/2', 'my-job-build 2/2', 'my-job-test', 'my-job-test-2', 'my-job-deploy'
)
end
context 'when passing some inputs multiple times' do
let(:inputs) do
[
{ key: 'deploy_strategy', value: 'blue-green' },
{ key: 'job_stage', value: 'deploy' },
{ key: 'test_script', value: ['echo "test"'] },
{ key: 'job_stage', value: 'test' }
]
end
it 'creates a pipeline using the inputs considering the last key' do
expect do
post_graphql_mutation(mutation, current_user: user)
end.to change { ::Ci::Pipeline.count }.by(1)
created_pipeline = ::Ci::Pipeline.last
expect(created_pipeline.stages.map(&:name)).to contain_exactly('test')
end
end
context 'when the FF ci_inputs_for_pipelines is disabled' do
before do
stub_feature_flags(ci_inputs_for_pipelines: false)
end
it 'behaves like the inputs are never passed and returns errors' do
post_graphql_mutation(mutation, current_user: user)
expect(mutation_response['errors'].first).to include(
'`deploy_strategy` input: required value has not been provided'
)
end
end
context 'when there are errors in the inputs' do
let(:inputs) do
[{ key: 'deploy_strategy', value: 'invalid' }]
end
it 'returns errors' do
post_graphql_mutation(mutation, current_user: user)
expect(mutation_response['errors'].first).to include(
'`deploy_strategy` input: `invalid` cannot be used because it is not in the list of allowed options'
)
expect(mutation_response['errors'].first).to include(
'`job_stage` input: required value has not been provided'
)
expect(mutation_response['errors'].first).to include(
'`test_script` input: required value has not been provided'
)
end
context 'when the FF ci_inputs_for_pipelines is disabled' do
before do
stub_feature_flags(ci_inputs_for_pipelines: false)
end
it 'behaves like the inputs are never passed and returns errors' do
post_graphql_mutation(mutation, current_user: user)
expect(mutation_response['errors'].first).to include(
'`deploy_strategy` input: required value has not been provided'
)
end
end
end
end
end
context 'when the `async` argument is `true`' do

View File

@ -78,7 +78,7 @@ RSpec.describe 'Query.work_item(id)', feature_category: :team_planning do
'reference' => work_item.to_reference,
'createNoteEmail' => work_item_email,
'archived' => false,
'userPermissions' => {
'userPermissions' => hash_including(
'readWorkItem' => true,
'updateWorkItem' => true,
'deleteWorkItem' => false,
@ -92,7 +92,7 @@ RSpec.describe 'Query.work_item(id)', feature_category: :team_planning do
'cloneWorkItem' => true,
'reportSpam' => false,
'summarizeComments' => false
},
),
'project' => hash_including('id' => project.to_gid.to_s, 'fullPath' => project.full_path)
)
end

View File

@ -109,9 +109,6 @@ mapping:
- source: 'data/whats_new/\w*\.yml'
test: 'spec/lib/release_highlights/validator_spec.rb'
# The documentation index page is used in this haml_lint spec
- source: 'doc/_index\.md'
test: 'spec/haml_lint/linter/documentation_links_spec.rb'
- source: '(?<prefix>ee/)?app/models/.+\.rb'
test: 'spec/models/every_model_spec.rb'