summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-11-30 15:07:02 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-11-30 15:07:02 +0000
commit826cf5293fb78029f76c5e769696e3b37e681207 (patch)
tree703bc997b5fa36c42e2bd7486f000ad41b01d252
parent7aa22e9a103b049dd2da70045a5822c51164f7db (diff)
downloadgitlab-ce-826cf5293fb78029f76c5e769696e3b37e681207.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_todo/gitlab/strong_memoize_attr.yml40
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.checksum2
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue6
-rw-r--r--app/assets/javascripts/repository/constants.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/plugins/link_dependencies.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/go_sum_linker.js33
-rw-r--r--app/models/ci/bridge.rb5
-rw-r--r--app/models/ci/build.rb1
-rw-r--r--app/models/hooks/service_hook.rb5
-rw-r--r--app/services/ci/pipeline_trigger_service.rb2
-rw-r--r--config/feature_flags/development/mirror_only_branches_match_regex.yml8
-rw-r--r--doc/api/merge_requests.md8
-rw-r--r--doc/api/project_import_export.md3
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-admin-area.md31
-rw-r--r--doc/user/analytics/dora_metrics.md2
-rw-r--r--doc/user/project/integrations/webhook_events.md2
-rw-r--r--doc/user/project/releases/index.md8
-rw-r--r--doc/user/project/repository/ssh_signed_commits/index.md78
-rw-r--r--doc/user/ssh.md2
-rw-r--r--lib/gitlab/data_builder/deployment.rb2
-rw-r--r--lib/gitlab/workhorse.rb26
-rw-r--r--locale/gitlab.pot15
-rw-r--r--rubocop/cop/gitlab/strong_memoize_attr.rb64
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/plugins/link_dependencies_spec.js53
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/plugins/mock_data.js2
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/plugins/utils/go_sum_linker_spec.js14
-rw-r--r--spec/lib/gitlab/data_builder/deployment_spec.rb8
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb20
-rw-r--r--spec/models/ci/bridge_spec.rb4
-rw-r--r--spec/models/ci/build_spec.rb1
-rw-r--r--spec/models/ci/processable_spec.rb2
-rw-r--r--spec/models/hooks/service_hook_spec.rb26
-rw-r--r--spec/requests/api/project_attributes.yml1
-rw-r--r--spec/requests/api/project_snapshots_spec.rb4
-rw-r--r--spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb7
-rw-r--r--spec/services/ci/create_downstream_pipeline_service_spec.rb8
-rw-r--r--spec/services/ci/pipeline_trigger_service_spec.rb2
-rw-r--r--workhorse/gitaly_integration_test.go1
-rw-r--r--workhorse/gitaly_test.go3
-rw-r--r--workhorse/internal/api/api.go9
-rw-r--r--workhorse/internal/git/archive.go6
-rw-r--r--workhorse/internal/git/blob.go6
-rw-r--r--workhorse/internal/git/diff.go6
-rw-r--r--workhorse/internal/git/format-patch.go6
-rw-r--r--workhorse/internal/git/info-refs.go7
-rw-r--r--workhorse/internal/git/receive-pack.go7
-rw-r--r--workhorse/internal/git/snapshot.go6
-rw-r--r--workhorse/internal/git/upload-pack.go7
-rw-r--r--workhorse/internal/gitaly/gitaly.go63
-rw-r--r--workhorse/internal/gitaly/gitaly_test.go87
-rw-r--r--workhorse/main_test.go1
54 files changed, 441 insertions, 280 deletions
diff --git a/.rubocop_todo/gitlab/strong_memoize_attr.yml b/.rubocop_todo/gitlab/strong_memoize_attr.yml
index df7e4b64ef0..1eeafaeedc3 100644
--- a/.rubocop_todo/gitlab/strong_memoize_attr.yml
+++ b/.rubocop_todo/gitlab/strong_memoize_attr.yml
@@ -32,6 +32,7 @@ Gitlab/StrongMemoizeAttr:
- 'app/controllers/projects/forks_controller.rb'
- 'app/controllers/projects/import/jira_controller.rb'
- 'app/controllers/projects/incidents_controller.rb'
+ - 'app/controllers/projects/merge_requests/drafts_controller.rb'
- 'app/controllers/projects/merge_requests_controller.rb'
- 'app/controllers/projects/metrics_dashboard_controller.rb'
- 'app/controllers/projects/milestones_controller.rb'
@@ -68,6 +69,8 @@ Gitlab/StrongMemoizeAttr:
- 'app/graphql/resolvers/work_items_resolver.rb'
- 'app/graphql/types/board_list_type.rb'
- 'app/helpers/appearances_helper.rb'
+ - 'app/helpers/broadcast_messages_helper.rb'
+ - 'app/helpers/diff_helper.rb'
- 'app/helpers/operations_helper.rb'
- 'app/helpers/page_layout_helper.rb'
- 'app/helpers/projects_helper.rb'
@@ -99,10 +102,12 @@ Gitlab/StrongMemoizeAttr:
- 'app/models/concerns/avatarable.rb'
- 'app/models/concerns/cascading_namespace_setting_attribute.rb'
- 'app/models/concerns/ci/contextable.rb'
+ - 'app/models/concerns/ci/partitionable.rb'
- 'app/models/concerns/discussion_on_diff.rb'
- 'app/models/concerns/has_repository.rb'
- 'app/models/concerns/has_wiki.rb'
- 'app/models/concerns/has_wiki_page_meta_attributes.rb'
+ - 'app/models/concerns/mentionable/reference_regexes.rb'
- 'app/models/concerns/redis_cacheable.rb'
- 'app/models/concerns/require_email_verification.rb'
- 'app/models/concerns/resolvable_discussion.rb'
@@ -131,6 +136,8 @@ Gitlab/StrongMemoizeAttr:
- 'app/models/merge_request.rb'
- 'app/models/merge_request_diff.rb'
- 'app/models/namespace.rb'
+ - 'app/models/namespaces/traversal/linear.rb'
+ - 'app/models/namespaces/traversal/recursive.rb'
- 'app/models/note.rb'
- 'app/models/onboarding/completion.rb'
- 'app/models/packages/go/module.rb'
@@ -145,6 +152,7 @@ Gitlab/StrongMemoizeAttr:
- 'app/models/snippet_input_action_collection.rb'
- 'app/models/state_note.rb'
- 'app/models/tree.rb'
+ - 'app/models/uploads/fog.rb'
- 'app/models/user.rb'
- 'app/models/wiki_page.rb'
- 'app/models/work_item.rb'
@@ -157,6 +165,7 @@ Gitlab/StrongMemoizeAttr:
- 'app/presenters/ci/pipeline_presenter.rb'
- 'app/presenters/clusters/cluster_presenter.rb'
- 'app/presenters/merge_request_presenter.rb'
+ - 'app/presenters/packages/conan/package_presenter.rb'
- 'app/presenters/packages/nuget/packages_metadata_presenter.rb'
- 'app/presenters/packages/nuget/search_results_presenter.rb'
- 'app/presenters/project_presenter.rb'
@@ -215,6 +224,7 @@ Gitlab/StrongMemoizeAttr:
- 'app/services/incident_management/issuable_escalation_statuses/prepare_update_service.rb'
- 'app/services/incident_management/pager_duty/process_webhook_service.rb'
- 'app/services/integrations/test/project_service.rb'
+ - 'app/services/issuable/discussions_list_service.rb'
- 'app/services/issues/reorder_service.rb'
- 'app/services/jira_connect_subscriptions/create_service.rb'
- 'app/services/jira_import/users_mapper_service.rb'
@@ -266,6 +276,7 @@ Gitlab/StrongMemoizeAttr:
- 'app/services/projects/container_repository/third_party/cleanup_tags_service.rb'
- 'app/services/projects/create_from_template_service.rb'
- 'app/services/projects/gitlab_projects_import_service.rb'
+ - 'app/services/projects/lfs_pointers/lfs_object_download_list_service.rb'
- 'app/services/projects/open_issues_count_service.rb'
- 'app/services/projects/record_target_platforms_service.rb'
- 'app/services/projects/update_remote_mirror_service.rb'
@@ -337,6 +348,7 @@ Gitlab/StrongMemoizeAttr:
- 'ee/app/helpers/ee/welcome_helper.rb'
- 'ee/app/helpers/license_monitoring_helper.rb'
- 'ee/app/helpers/paid_feature_callout_helper.rb'
+ - 'ee/app/helpers/subscriptions_helper.rb'
- 'ee/app/helpers/trial_status_widget_helper.rb'
- 'ee/app/models/approval_merge_request_rule.rb'
- 'ee/app/models/approval_state.rb'
@@ -345,6 +357,7 @@ Gitlab/StrongMemoizeAttr:
- 'ee/app/models/approval_wrapped_rule.rb'
- 'ee/app/models/approvals/scan_finding_wrapped_rule_set.rb'
- 'ee/app/models/approvals/wrapped_rule_set.rb'
+ - 'ee/app/models/burndown.rb'
- 'ee/app/models/ci/minutes/limit.rb'
- 'ee/app/models/concerns/deprecated_approvals_before_merge.rb'
- 'ee/app/models/concerns/ee/approvable.rb'
@@ -357,6 +370,7 @@ Gitlab/StrongMemoizeAttr:
- 'ee/app/models/ee/ci/build.rb'
- 'ee/app/models/ee/ci/build_dependencies.rb'
- 'ee/app/models/ee/ci/job_artifact.rb'
+ - 'ee/app/models/ee/ci/pipeline.rb'
- 'ee/app/models/ee/ci/runner.rb'
- 'ee/app/models/ee/deployment.rb'
- 'ee/app/models/ee/environment.rb'
@@ -408,7 +422,9 @@ Gitlab/StrongMemoizeAttr:
- 'ee/app/services/ee/projects/gitlab_projects_import_service.rb'
- 'ee/app/services/ee/protected_branches/create_service.rb'
- 'ee/app/services/ee/search/global_service.rb'
+ - 'ee/app/services/ee/search/group_service.rb'
- 'ee/app/services/ee/search_service.rb'
+ - 'ee/app/services/ee/users/authorized_build_service.rb'
- 'ee/app/services/ee/users/build_service.rb'
- 'ee/app/services/ee/users/update_service.rb'
- 'ee/app/services/elastic/cluster_reindexing_service.rb'
@@ -448,6 +464,7 @@ Gitlab/StrongMemoizeAttr:
- 'ee/app/services/vulnerability_feedback/destroy_service.rb'
- 'ee/app/workers/auth/saml_group_sync_worker.rb'
- 'ee/app/workers/geo/repository_cleanup_worker.rb'
+ - 'ee/app/workers/geo/scheduler/scheduler_worker.rb'
- 'ee/app/workers/group_saml_group_sync_worker.rb'
- 'ee/app/workers/status_page/publish_worker.rb'
- 'ee/lib/api/analytics/project_deployment_frequency.rb'
@@ -456,6 +473,7 @@ Gitlab/StrongMemoizeAttr:
- 'ee/lib/api/vulnerability_exports.rb'
- 'ee/lib/api/vulnerability_findings.rb'
- 'ee/lib/ee/api/geo.rb'
+ - 'ee/lib/ee/api/helpers.rb'
- 'ee/lib/ee/banzai/filter/references/reference_cache.rb'
- 'ee/lib/ee/container_registry/client.rb'
- 'ee/lib/ee/gitlab/alert_management/payload/generic.rb'
@@ -499,10 +517,13 @@ Gitlab/StrongMemoizeAttr:
- 'ee/lib/gitlab/code_owners/entry.rb'
- 'ee/lib/gitlab/code_owners/loader.rb'
- 'ee/lib/gitlab/custom_file_templates.rb'
+ - 'ee/lib/gitlab/elastic/client.rb'
- 'ee/lib/gitlab/elastic/document_reference.rb'
- 'ee/lib/gitlab/elastic/indexer.rb'
+ - 'ee/lib/gitlab/elastic/project_search_results.rb'
- 'ee/lib/gitlab/elastic/search_results.rb'
- 'ee/lib/gitlab/expiring_subscription_message.rb'
+ - 'ee/lib/gitlab/geo.rb'
- 'ee/lib/gitlab/geo/health_check.rb'
- 'ee/lib/gitlab/geo/jwt_request_decoder.rb'
- 'ee/lib/gitlab/geo/oauth/logout_state.rb'
@@ -528,6 +549,7 @@ Gitlab/StrongMemoizeAttr:
- 'lib/api/composer_packages.rb'
- 'lib/api/container_repositories.rb'
- 'lib/api/entities/basic_project_details.rb'
+ - 'lib/api/helpers/authentication.rb'
- 'lib/api/helpers/packages/basic_auth_helpers.rb'
- 'lib/api/helpers/packages/conan/api_helpers.rb'
- 'lib/api/helpers/packages/npm.rb'
@@ -542,6 +564,7 @@ Gitlab/StrongMemoizeAttr:
- 'lib/banzai/filter/issuable_reference_expansion_filter.rb'
- 'lib/banzai/filter/references/reference_cache.rb'
- 'lib/banzai/filter/repository_link_filter.rb'
+ - 'lib/banzai/reference_parser/merge_request_parser.rb'
- 'lib/bulk_imports/clients/http.rb'
- 'lib/bulk_imports/pipeline.rb'
- 'lib/bulk_imports/users_mapper.rb'
@@ -557,6 +580,7 @@ Gitlab/StrongMemoizeAttr:
- 'lib/gitlab/analytics/cycle_analytics/average.rb'
- 'lib/gitlab/analytics/cycle_analytics/data_collector.rb'
- 'lib/gitlab/analytics/cycle_analytics/records_fetcher.rb'
+ - 'lib/gitlab/analytics/cycle_analytics/request_params.rb'
- 'lib/gitlab/application_context.rb'
- 'lib/gitlab/auth/atlassian/identity_linker.rb'
- 'lib/gitlab/auth/auth_finders.rb'
@@ -598,8 +622,10 @@ Gitlab/StrongMemoizeAttr:
- 'lib/gitlab/ci/pipeline/chain/limit/active_jobs.rb'
- 'lib/gitlab/ci/pipeline/chain/limit/rate_limit.rb'
- 'lib/gitlab/ci/pipeline/chain/seed.rb'
+ - 'lib/gitlab/ci/pipeline/chain/skip.rb'
- 'lib/gitlab/ci/pipeline/expression/lexer.rb'
- 'lib/gitlab/ci/pipeline/logger.rb'
+ - 'lib/gitlab/ci/pipeline/metrics.rb'
- 'lib/gitlab/ci/pipeline/quota/deployments.rb'
- 'lib/gitlab/ci/pipeline/seed/build.rb'
- 'lib/gitlab/ci/pipeline/seed/pipeline.rb'
@@ -611,6 +637,7 @@ Gitlab/StrongMemoizeAttr:
- 'lib/gitlab/ci/project_config/remote.rb'
- 'lib/gitlab/ci/project_config/repository.rb'
- 'lib/gitlab/ci/project_config/source.rb'
+ - 'lib/gitlab/ci/queue/metrics.rb'
- 'lib/gitlab/ci/reports/accessibility_reports_comparer.rb'
- 'lib/gitlab/ci/reports/codequality_reports_comparer.rb'
- 'lib/gitlab/ci/reports/security/locations/base.rb'
@@ -618,10 +645,13 @@ Gitlab/StrongMemoizeAttr:
- 'lib/gitlab/ci/reports/test_reports_comparer.rb'
- 'lib/gitlab/ci/reports/test_suite_comparer.rb'
- 'lib/gitlab/ci/reports/test_suite_summary.rb'
+ - 'lib/gitlab/ci/runner/metrics.rb'
+ - 'lib/gitlab/ci/status/composite.rb'
- 'lib/gitlab/ci/tags/bulk_insert.rb'
- 'lib/gitlab/ci/trace.rb'
- 'lib/gitlab/ci/trace/archive.rb'
- 'lib/gitlab/ci/trace/checksum.rb'
+ - 'lib/gitlab/ci/trace/metrics.rb'
- 'lib/gitlab/ci/trace/remote_checksum.rb'
- 'lib/gitlab/ci/variables/builder.rb'
- 'lib/gitlab/ci/variables/builder/group.rb'
@@ -634,7 +664,9 @@ Gitlab/StrongMemoizeAttr:
- 'lib/gitlab/config/entry/composable_array.rb'
- 'lib/gitlab/config/loader/yaml.rb'
- 'lib/gitlab/conflict/file.rb'
+ - 'lib/gitlab/database/as_with_materialized.rb'
- 'lib/gitlab/database/background_migration/health_status/indicators/write_ahead_log.rb'
+ - 'lib/gitlab/database/background_migration/prometheus_metrics.rb'
- 'lib/gitlab/database/bulk_update.rb'
- 'lib/gitlab/database/load_balancing/srv_resolver.rb'
- 'lib/gitlab/database/metrics.rb'
@@ -650,12 +682,14 @@ Gitlab/StrongMemoizeAttr:
- 'lib/gitlab/diff/suggestion.rb'
- 'lib/gitlab/discussions_diff/file_collection.rb'
- 'lib/gitlab/email/handler/service_desk_handler.rb'
+ - 'lib/gitlab/email/hook/delivery_metrics_observer.rb'
- 'lib/gitlab/email/receiver.rb'
- 'lib/gitlab/external_authorization/response.rb'
- 'lib/gitlab/gfm/reference_rewriter.rb'
- 'lib/gitlab/gfm/uploads_rewriter.rb'
- 'lib/gitlab/git/commit.rb'
- 'lib/gitlab/git/diff_stats_collection.rb'
+ - 'lib/gitlab/git/merge_base.rb'
- 'lib/gitlab/git/push.rb'
- 'lib/gitlab/git/repository.rb'
- 'lib/gitlab/git/wiki_page_version.rb'
@@ -689,10 +723,12 @@ Gitlab/StrongMemoizeAttr:
- 'lib/gitlab/kubernetes/deployment.rb'
- 'lib/gitlab/kubernetes/ingress.rb'
- 'lib/gitlab/kubernetes/rollout_instances.rb'
+ - 'lib/gitlab/language_data.rb'
- 'lib/gitlab/lets_encrypt/client.rb'
- 'lib/gitlab/metrics/dashboard/stages/grafana_formatter.rb'
- 'lib/gitlab/metrics/dashboard/url.rb'
- 'lib/gitlab/metrics/prometheus.rb'
+ - 'lib/gitlab/metrics/subscribers/active_record.rb'
- 'lib/gitlab/pages/cache_control.rb'
- 'lib/gitlab/prometheus_client.rb'
- 'lib/gitlab/rack_attack/request.rb'
@@ -702,7 +738,9 @@ Gitlab/StrongMemoizeAttr:
- 'lib/gitlab/relative_positioning/starting_from.rb'
- 'lib/gitlab/request_context.rb'
- 'lib/gitlab/search/found_blob.rb'
+ - 'lib/gitlab/search/parsed_query.rb'
- 'lib/gitlab/serverless/service.rb'
+ - 'lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb'
- 'lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/deduplicates_when_scheduling.rb'
- 'lib/gitlab/sidekiq_queue.rb'
- 'lib/gitlab/signed_commit.rb'
@@ -715,7 +753,9 @@ Gitlab/StrongMemoizeAttr:
- 'lib/gitlab/web_hooks/rate_limiter.rb'
- 'lib/gitlab/web_ide/config/entry/terminal.rb'
- 'lib/gitlab/webpack/graphql_known_operations.rb'
+ - 'lib/gitlab/webpack/manifest.rb'
- 'lib/gitlab/wiki_pages/front_matter_parser.rb'
+ - 'lib/gitlab/x509/certificate.rb'
- 'lib/gitlab/x509/signature.rb'
- 'lib/gitlab/x509/tag.rb'
- 'lib/grafana/time_window.rb'
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index cabdb0c1288..74b94df5f28 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-ff3095c307c9223585ffe01d3e013929aa6279d8
+942f8800cc11d161785823fe8f65a77b5cb83718
diff --git a/Gemfile b/Gemfile
index fd79c756466..ebbd40c39ef 100644
--- a/Gemfile
+++ b/Gemfile
@@ -19,7 +19,7 @@ gem 'bootsnap', '~> 1.15.0', require: false
# Pin openssl to match the version bundled with our supported Rubies.
# See https://stdgems.org/openssl/#gem-version.
-gem 'openssl', '2.2.1'
+gem 'openssl', '2.2.2'
# This gem was originally bundled with Ruby 2.7, but is unbundled as of Ruby 3.
# Since the latest version caused problems with GitLab, we pin this to an older
# version for now.
diff --git a/Gemfile.checksum b/Gemfile.checksum
index 73608acb159..de417277434 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -403,7 +403,7 @@
{"name":"omniauth-twitter","version":"1.4.0","platform":"ruby","checksum":"c5cc6c77cd767745ffa9ebbd5fbd694a3fa99d1d2d82a4d7def0bf3b6131b264"},
{"name":"open4","version":"1.3.4","platform":"ruby","checksum":"a1df037310624ecc1ea1d81264b11c83e96d0c3c1c6043108d37d396dcd0f4b1"},
{"name":"openid_connect","version":"1.3.0","platform":"ruby","checksum":"a796855096850cc01140e37ea6ae9fd14f2be818b9b5bc698418063dfe228770"},
-{"name":"openssl","version":"2.2.1","platform":"ruby","checksum":"f6afbf4b66f3fcd3c08dc1da1ddd2245b76c19d0ea2dd7e2c8b55794ca1a7d72"},
+{"name":"openssl","version":"2.2.2","platform":"ruby","checksum":"53f72382bac046c36c37049c7ec9d5597d42628d140b5cfbcd61e0226c0ca077"},
{"name":"openssl-signature_algorithm","version":"0.4.0","platform":"ruby","checksum":"e53a225b773784935249cf4c61238c6cf0e1e464e78ae2f8ddaf995fb22ca991"},
{"name":"opentracing","version":"0.5.0","platform":"ruby","checksum":"deb5d7abe6b0e7631d866d8cb5ee7bb9352650a504a32f61591302bc510b9286"},
{"name":"optimist","version":"3.0.1","platform":"ruby","checksum":"336b753676d6117cad9301fac7e91dab4228f747d4e7179891ad3a163c64e2ed"},
diff --git a/Gemfile.lock b/Gemfile.lock
index 94610975c23..beab0c53eac 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1028,7 +1028,7 @@ GEM
validate_email
validate_url
webfinger (>= 1.0.1)
- openssl (2.2.1)
+ openssl (2.2.2)
ipaddr
openssl-signature_algorithm (0.4.0)
opentracing (0.5.0)
@@ -1763,7 +1763,7 @@ DEPENDENCIES
omniauth-shibboleth (~> 1.3.0)
omniauth-twitter (~> 1.4)
omniauth_crowd (~> 2.4.0)!
- openssl (= 2.2.1)
+ openssl (= 2.2.2)
org-ruby (~> 0.9.12)
pact (~> 1.63)
parallel (~> 1.19)
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue b/app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue
index 1afc1c9a595..c9172fe0322 100644
--- a/app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue
+++ b/app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue
@@ -2,9 +2,7 @@
import { GlButton, GlTableLite } from '@gitlab/ui';
import { __ } from '~/locale';
-const DEFAULT_TD_CLASSES = 'gl-w-half gl-font-sm! gl-border-gray-200!';
-const DEFAULT_TH_CLASSES =
- 'gl-bg-transparent! gl-border-b-solid! gl-border-b-gray-200! gl-border-b-1!';
+const DEFAULT_TD_CLASSES = 'gl-font-sm!';
export default {
fields: [
@@ -13,14 +11,12 @@ export default {
label: __('Key'),
tdAttr: { 'data-testid': 'trigger-build-key' },
tdClass: DEFAULT_TD_CLASSES,
- thClass: DEFAULT_TH_CLASSES,
},
{
key: 'value',
label: __('Value'),
tdAttr: { 'data-testid': 'trigger-build-value' },
tdClass: DEFAULT_TD_CLASSES,
- thClass: DEFAULT_TH_CLASSES,
},
],
components: {
diff --git a/app/assets/javascripts/repository/constants.js b/app/assets/javascripts/repository/constants.js
index 3a6d7d2f779..e194bddcc56 100644
--- a/app/assets/javascripts/repository/constants.js
+++ b/app/assets/javascripts/repository/constants.js
@@ -99,5 +99,4 @@ export const LEGACY_FILE_TYPES = [
'requirements_txt',
'cargo_toml',
'go_mod',
- 'go_sum',
];
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/link_dependencies.js b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/link_dependencies.js
index fca2616f069..cd15916851c 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/link_dependencies.js
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/link_dependencies.js
@@ -4,6 +4,7 @@ import godepsJsonLinker from './utils/godeps_json_linker';
import gemfileLinker from './utils/gemfile_linker';
import podspecJsonLinker from './utils/podspec_json_linker';
import composerJsonLinker from './utils/composer_json_linker';
+import goSumLinker from './utils/go_sum_linker';
const DEPENDENCY_LINKERS = {
package_json: packageJsonLinker,
@@ -12,6 +13,7 @@ const DEPENDENCY_LINKERS = {
gemfile: gemfileLinker,
podspec_json: podspecJsonLinker,
composer_json: composerJsonLinker,
+ go_sum: goSumLinker,
};
/**
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/go_sum_linker.js b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/go_sum_linker.js
new file mode 100644
index 00000000000..c0e3eadb3b3
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/go_sum_linker.js
@@ -0,0 +1,33 @@
+import { createLink } from './dependency_linker_util';
+
+const openTag = '<span class="">';
+const closeTag = '</span>';
+const TAG_URL = 'https://sum.golang.org/lookup/';
+const GO_PACKAGE_URL = 'https://pkg.go.dev/';
+
+const DEPENDENCY_REGEX = new RegExp(
+ /*
+ * Detects dependencies inside of content that is highlighted by Highlight.js
+ * Example: '<span class="">cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=</span>'
+ * Group 1 (packageName): 'cloud.google.com/go/bigquery'
+ * Group 2 (version): 'v1.0.1/go.mod'
+ * Group 3 (base64url): 'i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o='
+ */
+ `${openTag}(.*) (v.*) h1:(.*)${closeTag}`,
+ 'gm',
+);
+
+const handleReplace = (packageName, version, tag) => {
+ const packageHref = `${GO_PACKAGE_URL}${packageName}`;
+ const packageLink = createLink(packageHref, packageName);
+ const tagHref = `${TAG_URL}${packageName}@${version.split('/go.mod')[0]}`;
+ const tagLink = createLink(tagHref, tag);
+
+ return `${openTag}${packageLink} ${version} h1:${tagLink}${closeTag}`;
+};
+
+export default (result) => {
+ return result.value.replace(DEPENDENCY_REGEX, (_, packageName, version, tag) =>
+ handleReplace(packageName, version, tag),
+ );
+};
diff --git a/app/models/ci/bridge.rb b/app/models/ci/bridge.rb
index 22dcc7c18a0..1da1e7dda53 100644
--- a/app/models/ci/bridge.rb
+++ b/app/models/ci/bridge.rb
@@ -18,6 +18,9 @@ module Ci
belongs_to :project
belongs_to :trigger_request
+ has_many :sourced_pipelines, class_name: "::Ci::Sources::Pipeline",
+ foreign_key: :source_job_id,
+ inverse_of: :source_bridge
has_one :downstream_pipeline, through: :sourced_pipeline, source: :pipeline
@@ -85,7 +88,7 @@ module Ci
end
def has_downstream_pipeline?
- sourced_pipeline.present?
+ sourced_pipelines.exists?
end
def downstream_pipeline_params
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 40b46a3a342..3aa42db7b88 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -47,6 +47,7 @@ module Ci
# Details: https://gitlab.com/gitlab-org/gitlab/-/issues/24644#note_689472685
has_many :job_artifacts, class_name: 'Ci::JobArtifact', foreign_key: :job_id, dependent: :destroy, inverse_of: :job # rubocop:disable Cop/ActiveRecordDependent
has_many :job_variables, class_name: 'Ci::JobVariable', foreign_key: :job_id
+ has_many :sourced_pipelines, class_name: 'Ci::Sources::Pipeline', foreign_key: :source_job_id
has_many :pages_deployments, inverse_of: :ci_build
diff --git a/app/models/hooks/service_hook.rb b/app/models/hooks/service_hook.rb
index 27119d3a95a..94ced96bbde 100644
--- a/app/models/hooks/service_hook.rb
+++ b/app/models/hooks/service_hook.rb
@@ -13,4 +13,9 @@ class ServiceHook < WebHook
override :parent
delegate :parent, to: :integration
+
+ override :executable?
+ def executable?
+ true
+ end
end
diff --git a/app/services/ci/pipeline_trigger_service.rb b/app/services/ci/pipeline_trigger_service.rb
index fae3ae3bf02..d7065680053 100644
--- a/app/services/ci/pipeline_trigger_service.rb
+++ b/app/services/ci/pipeline_trigger_service.rb
@@ -62,7 +62,7 @@ module Ci
response = Ci::CreatePipelineService
.new(project, job.user, ref: params[:ref], variables_attributes: variables)
.execute(:pipeline, ignore_skip_ci: true) do |pipeline|
- source = job.build_sourced_pipeline(
+ source = job.sourced_pipelines.build(
source_pipeline: job.pipeline,
source_project: job.project,
pipeline: pipeline,
diff --git a/config/feature_flags/development/mirror_only_branches_match_regex.yml b/config/feature_flags/development/mirror_only_branches_match_regex.yml
new file mode 100644
index 00000000000..6494569b364
--- /dev/null
+++ b/config/feature_flags/development/mirror_only_branches_match_regex.yml
@@ -0,0 +1,8 @@
+---
+name: mirror_only_branches_match_regex
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99201
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381667
+milestone: '15.6'
+type: development
+group: "group::source code"
+default_enabled: false
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 6ee74cc73ce..c205ed625ff 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -971,6 +971,10 @@ Supported attributes:
## Get single merge request changes
+WARNING:
+This endpoint was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/322117) in GitLab 15.7
+and will be removed in API v5. Use the [List merge request diffs](#list-merge-request-diffs) endpoint instead.
+
Shows information about the merge request including its files and changes.
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46190) in GitLab 13.6,
@@ -1101,10 +1105,6 @@ Supported attributes:
}
```
-WARNING:
-This endpoint was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/322117) in GitLab 15.7
-and will be removed in API v5. Use the [List merge request diffs](#list-merge-request-diffs) endpoint instead.
-
## List merge request diffs
List diffs of the files changed in a merge request.
diff --git a/doc/api/project_import_export.md b/doc/api/project_import_export.md
index 1106e306d4e..a14f385cdb5 100644
--- a/doc/api/project_import_export.md
+++ b/doc/api/project_import_export.md
@@ -30,6 +30,9 @@ project to a web server or to any S3-compatible platform. For exports, GitLab:
The `upload[url]` parameter is required if the `upload` parameter is present.
+For uploads to Amazon S3, refer to [Generating a pre-signed URL for uploading objects](https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html)
+documentation scripts to generate the `upload[url]`.
+
```plaintext
POST /projects/:id/export
```
diff --git a/doc/architecture/blueprints/pods/pods-feature-admin-area.md b/doc/architecture/blueprints/pods/pods-feature-admin-area.md
index 6457f02f7cc..7efaa383510 100644
--- a/doc/architecture/blueprints/pods/pods-feature-admin-area.md
+++ b/doc/architecture/blueprints/pods/pods-feature-admin-area.md
@@ -14,14 +14,43 @@ we can document the reasons for not choosing this approach.
# Pods: Admin Area
-> TL;DR
+In our Pods architecture proposal we plan to share all admin related tables in
+GitLab. This allows simpler management of all Pods in one interface and reduces
+the risk of settings diverging in different Pods. This introduces challenges
+with admin pages that allow you to manage data that will be spread across all
+Pods.
## 1. Definition
+There are consequences for admin pages that contain data that spans "the whole
+instance" as the Admin pages may be served by any Pod or possibly just 1 pod.
+There are already many parts of the Admin interface that will have data that
+spans many pods. For example lists of all Groups, Projects, Topics, Jobs,
+Analytics, Applications and more. There are also administrative monitoring
+capabilities in the Admin page that will span many pods such as the "Background
+Jobs" and "Background Migrations" pages.
+
## 2. Data flow
## 3. Proposal
+We will need to decide how to handle these exceptions with a few possible
+options:
+
+1. Move all these pages out into a dedicated per-pod Admin section. Probably
+ the URL will need to be routable to a single Pod like `/pods/<pod_id>/admin`,
+ then we can display this data per Pod. These pages will be distinct from
+ other Admin pages which control settings that are shared across all Pods. We
+ will also need to consider how this impacts self-managed customers and
+ whether, or not, this should be visible for single-pod instances of GitLab.
+1. Build some aggregation interfaces for this data so that it can be fetched
+ from all Pods and presented in a single UI. This may be beneficial to an
+ administrator that needs to see and filter all data at a glance, especially
+ when they don't know which Pod the data is on. The downside, however, is
+ that building this kind of aggregation is very tricky when all the Pods are
+ designed to be totally independent, and it does also enforce more strict
+ requirements on compatibility between Pods.
+
## 4. Evaluation
## 4.1. Pros
diff --git a/doc/user/analytics/dora_metrics.md b/doc/user/analytics/dora_metrics.md
index b5f37203817..a2b2762e6da 100644
--- a/doc/user/analytics/dora_metrics.md
+++ b/doc/user/analytics/dora_metrics.md
@@ -113,7 +113,7 @@ With this new visualization, software leaders can track metrics improvements, un
Deployment frequency is calculated based on the deployments record, which is created for typical push-based deployments.
These deployment records are not created for pull-based deployments, for example when Container Images are connected to GitLab with an agent.
-To track DORA metrics in these cases, you can [create a deployment record](../../api/deployments.md#create-a-deployment) using the Deployments API.
+To track DORA metrics in these cases, you can [create a deployment record](../../api/deployments.md#create-a-deployment) using the Deployments API. See also the documentation page for [Track deployments of an external deployment tool](../../ci/environments/external_deployment_tools.md).
### Supported DORA metrics in GitLab
diff --git a/doc/user/project/integrations/webhook_events.md b/doc/user/project/integrations/webhook_events.md
index 60187b9a682..65faf658bea 100644
--- a/doc/user/project/integrations/webhook_events.md
+++ b/doc/user/project/integrations/webhook_events.md
@@ -1475,6 +1475,8 @@ Payload example:
"deployable_id": 796,
"deployable_url": "http://10.126.0.2:3000/root/test-deployment-webhooks/-/jobs/796",
"environment": "staging",
+ "environment_slug": "staging",
+ "environment_external_url": "https://staging.example.com",
"project": {
"id": 30,
"name": "test-deployment-webhooks",
diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md
index 75a25678125..da00be361f3 100644
--- a/doc/user/project/releases/index.md
+++ b/doc/user/project/releases/index.md
@@ -209,11 +209,15 @@ Prerequisites:
- You must have at least the Developer role. Read more about [Release permissions](#release-permissions).
-To delete a release in the UI:
+To delete a release, use either the
+[Delete a release API](../../../api/releases/index.md#delete-a-release) or the UI.
+
+In the UI:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Deployments > Releases**.
-1. In the top-right corner of the release you want to delete, select **Edit this release** (**{pencil}**).
+1. In the top-right corner of the release you want to delete, select **Edit this release**
+ (**{pencil}**).
1. On the **Edit Release** page, select **Delete**.
1. Select **Delete release**.
diff --git a/doc/user/project/repository/ssh_signed_commits/index.md b/doc/user/project/repository/ssh_signed_commits/index.md
index 4c7e07da7f1..81651058434 100644
--- a/doc/user/project/repository/ssh_signed_commits/index.md
+++ b/doc/user/project/repository/ssh_signed_commits/index.md
@@ -8,6 +8,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/343879) in GitLab 15.7 [with a flag](../../../../administration/feature_flags.md) named `ssh_commit_signatures`. Disabled by default.
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available,
+ask an administrator to [enable the feature flag](../../../../administration/feature_flags.md) named `ssh_commit_signatures`.
+On GitLab.com, this feature is available.
+
Use SSH keys to sign Git commits in the same manner as
[GPG signed commits](../gpg_signed_commits/index.md). When you sign commits
with SSH keys, GitLab uses the SSH public keys associated with your
@@ -15,16 +20,18 @@ GitLab account to cryptographically verify the commit signature.
If successful, GitLab displays a **Verified** label on the commit.
You may use the same SSH keys for `git+ssh` authentication to GitLab
-and signing commit signatures.
+and signing commit signatures as long as their usage type is **Authentication & Signing**.
+It can be verified on the page for [adding an SSH key to your GitLab account](../../../ssh.md#add-an-ssh-key-to-your-gitlab-account).
To learn more about managing the SSH keys associated with your GitLab account, read
[use SSH keys to communicate with GitLab](../../../ssh.md).
## Configure Git to sign commits with your SSH key
-After you have [created an SSH key](../../../ssh.md#generate-an-ssh-key-pair) and
-[added it to your GitLab account](../../../ssh.md#add-an-ssh-key-to-your-gitlab-account),
-you need to configure Git to begin using it.
+After you [create an SSH key](../../../ssh.md#generate-an-ssh-key-pair) and
+[add it to your GitLab account](../../../ssh.md#add-an-ssh-key-to-your-gitlab-account)
+or [generate it using a password manager](../../../ssh.md#generate-an-ssh-key-pair-with-a-password-manager),
+configure Git to begin using the key.
Prerequisites:
@@ -34,11 +41,12 @@ Prerequisites:
NOTE:
OpenSSH 8.7 has broken signing functionality. If you are on OpenSSH 8.7, upgrade to OpenSSH 8.8.
-- A SSH key of one of these types:
+- A SSH key with the usage type of either **Authentication & Signing** or **Signing**.
+ The SSH key must be one of these types:
- [ED25519](../../../ssh.md#ed25519-ssh-keys) (recommended)
- [RSA](../../../ssh.md#rsa-ssh-keys)
-To configure Git:
+To configure Git to use your key:
1. Configure Git to use SSH for commit signing:
@@ -79,7 +87,9 @@ To sign a commit:
1. If your SSH key is protected, Git prompts you to enter your passphrase.
1. Push to GitLab.
-1. Check that your commits [are verified](../gpg_signed_commits/index.md#verify-commits).
+1. Check that your commits [are verified](#verify-commits).
+ Signature verification uses the `allowed_signers` file to associate emails and SSH keys.
+ For help configuring this file, read [Verify commits locally](#verify-commits-locally).
## Verify commits
@@ -96,10 +106,62 @@ they are signed:
1. Identify the commit you want to review. Signed commits show either a **Verified**
or **Unverified** badge, depending on the verification status of the signature.
Unsigned commits do not display a badge.
-
1. To display the signature details for a commit, select **Verified**. GitLab shows
the SSH key's fingerprint.
+## Verify commits locally
+
+To verify commits locally, create an
+[allowed signers file](https://man7.org/linux/man-pages/man1/ssh-keygen.1.html#ALLOWED_SIGNERS)
+for Git to associate SSH public keys with users:
+
+1. Create an allowed signers file:
+
+ ```shell
+ touch allowed_signers
+ ```
+
+1. Configure the `allowed_signers` file in Git:
+
+ ```shell
+ git config gpg.ssh.allowedSignersFile "$(pwd)/allowed_signers"
+ ```
+
+1. Add your entry to the allowed signers file. Use this command to add your
+ email address and public SSH key to the `allowed_signers` file. Replace `<MY_KEY>`
+ with the name of your key, and `~/.ssh/allowed_signers`
+ with the location of your project's `allowed_signers` file:
+
+ ```shell
+ # Modify this line to meet your needs.
+ # Declaring the `git` namespace helps prevent cross-protocol attacks.
+ echo "$(git config --get user.email) namespaces=\"git\" $(cat ~/.ssh/<MY_KEY>.pub)" >> ~/.ssh/allowed_signers
+ ```
+
+ The resulting entry in the `allowed_signers` file contains your email address, key type,
+ and key contents, like this:
+
+ ```plaintext
+ example@gitlab.com namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAmaTS47vRmsKyLyK1jlIFJn/i8wdGQ3J49LYyIYJ2hv
+ ```
+
+1. Repeat the previous step for each user who you want to verify signatures for.
+ Consider checking this file in to your Git repository if you want to locally
+ verify signatures for many different contributors.
+
+1. Use `git log --show-signature` to view the signature status for the commits:
+
+ ```shell
+ $ git log --show-signature
+
+ commit e2406b6cd8ebe146835ceab67ff4a5a116e09154 (HEAD -> main, origin/main, origin/HEAD)
+ Good "git" signature for johndoe@example.com with ED25519 key SHA256:Ar44iySGgxic+U6Dph4Z9Rp+KDaix5SFGFawovZLAcc
+ Author: John Doe <johndoe@example.com>
+ Date: Tue Nov 29 06:54:15 2022 -0600
+
+ SSH signed commit
+ ```
+
## Revoke an SSH key for signing commits
You can't revoke an SSH key used for signing commits. To learn more, read
diff --git a/doc/user/ssh.md b/doc/user/ssh.md
index 85332446334..1d82d301e9a 100644
--- a/doc/user/ssh.md
+++ b/doc/user/ssh.md
@@ -270,6 +270,7 @@ You can use [1Password](https://1password.com/) and the [1Password browser exten
1. You can then select **Create SSH Key** or select an existing SSH key to fill in the public key.
1. In the **Title** box, type a description, like `Work Laptop` or
`Home Workstation`.
+1. Optional. Select the **Usage type** of the key. It can be used either for `Authentication` or `Signing` or both. `Authentication & Signing` is the default value.
1. Optional. Update **Expiration date** to modify the default expiration date.
1. Select **Add key**.
@@ -314,6 +315,7 @@ To use SSH with GitLab, copy your public key to your GitLab account:
`ssh-ed25519`, `sk-ecdsa-sha2-nistp256@openssh.com`, or `sk-ssh-ed25519@openssh.com`, and may end with a comment.
1. In the **Title** box, type a description, like `Work Laptop` or
`Home Workstation`.
+1. Optional. Select the **Usage type** of the key. It can be used either for `Authentication` or `Signing` or both. `Authentication & Signing` is the default value.
1. Optional. Update **Expiration date** to modify the default expiration date.
In:
- GitLab 13.12 and earlier, the expiration date is informational only. It doesn't prevent
diff --git a/lib/gitlab/data_builder/deployment.rb b/lib/gitlab/data_builder/deployment.rb
index a9c69e3f997..7055f64937d 100644
--- a/lib/gitlab/data_builder/deployment.rb
+++ b/lib/gitlab/data_builder/deployment.rb
@@ -35,6 +35,8 @@ module Gitlab
deployable_id: deployment.deployable_id,
deployable_url: deployable_url,
environment: deployment.environment.name,
+ environment_slug: deployment.environment.slug,
+ environment_external_url: deployment.environment.external_url,
project: deployment.project.hook_attrs,
short_sha: deployment.short_sha,
user: deployment.deployed_by&.hook_attrs,
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index fb3fbc80d24..02418c45e73 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -33,7 +33,7 @@ module Gitlab
GitalyServer: {
address: Gitlab::GitalyClient.address(repository.storage),
token: Gitlab::GitalyClient.token(repository.storage),
- features: Feature::Gitaly.server_feature_flags(
+ call_metadata: Feature::Gitaly.server_feature_flags(
user: ::Feature::Gitaly.user_actor(user),
repository: repository,
project: ::Feature::Gitaly.project_actor(repository.container),
@@ -48,14 +48,11 @@ module Gitlab
attrs[:GitConfigOptions] << "receive.maxInputSize=#{receive_max_input_size.megabytes}"
end
- remote_ip = Gitlab::ApplicationContext.current_context_attribute(:remote_ip)
- attrs[:RemoteIP] = remote_ip if remote_ip.present?
-
- attrs[:GitalyServer][:call_metadata] = attrs[:GitalyServer][:features].merge(
+ attrs[:GitalyServer][:call_metadata].merge!(
'user_id' => attrs[:GL_ID].presence,
'username' => attrs[:GL_USERNAME].presence,
- 'remote_ip' => attrs[:RemoteIP]
- ).compact
+ 'remote_ip' => Gitlab::ApplicationContext.current_context_attribute(:remote_ip).presence
+ ).compact!
attrs
end
@@ -263,18 +260,15 @@ module Gitlab
end
def gitaly_server_hash(repository)
- features = Feature::Gitaly.server_feature_flags(
- user: ::Feature::Gitaly.user_actor,
- repository: repository,
- project: ::Feature::Gitaly.project_actor(repository.container),
- group: ::Feature::Gitaly.group_actor(repository.container)
- )
-
{
address: Gitlab::GitalyClient.address(repository.shard),
token: Gitlab::GitalyClient.token(repository.shard),
- features: features,
- call_metadata: features
+ call_metadata: Feature::Gitaly.server_feature_flags(
+ user: ::Feature::Gitaly.user_actor,
+ repository: repository,
+ project: ::Feature::Gitaly.project_actor(repository.container),
+ group: ::Feature::Gitaly.group_actor(repository.container)
+ )
}
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 31afdb16aba..9a37d9d0ef0 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -720,6 +720,12 @@ msgstr ""
msgid "%{host} sign-in from new location"
msgstr ""
+msgid "%{human_readable_key} exceeds %{max_value_length} characters"
+msgstr ""
+
+msgid "%{human_readable_key} is less than %{min_value_length} characters"
+msgstr ""
+
msgid "%{integrations_link_start}Integrations%{link_end} enable you to make third-party applications part of your GitLab workflow. If the available integrations don't meet your needs, consider using a %{webhooks_link_start}webhook%{link_end}."
msgstr ""
@@ -24006,6 +24012,9 @@ msgstr ""
msgid "Last event"
msgstr ""
+msgid "Last login"
+msgstr ""
+
msgid "Last modified"
msgstr ""
@@ -34769,6 +34778,9 @@ msgstr ""
msgid "Request Access"
msgstr ""
+msgid "Request Headers"
+msgstr ""
+
msgid "Request a new one"
msgstr ""
@@ -48689,9 +48701,6 @@ msgstr ""
msgid "exceeds maximum length (100 usernames)"
msgstr ""
-msgid "exceeds the %{max_value_length} character limit"
-msgstr ""
-
msgid "exceeds the limit of %{bytes} bytes"
msgstr ""
diff --git a/rubocop/cop/gitlab/strong_memoize_attr.rb b/rubocop/cop/gitlab/strong_memoize_attr.rb
index 2da7f71b920..c98aa4765fa 100644
--- a/rubocop/cop/gitlab/strong_memoize_attr.rb
+++ b/rubocop/cop/gitlab/strong_memoize_attr.rb
@@ -3,34 +3,68 @@
module RuboCop
module Cop
module Gitlab
- # Cop that disallows functions that contain only a call to `strong_memoize()`, in favor
- # of `strong_memoize_attr()`.
+ # Prefer using `.strong_memoize_attr()` over `#strong_memoize()`. See
+ # https://docs.gitlab.com/ee/development/utilities.html/#strongmemoize.
+ #
+ # Good:
+ #
+ # def memoized_method
+ # 'This is a memoized method'
+ # end
+ # strong_memoize_attr :memoized_method
+ #
+ # Bad, can be autocorrected:
+ #
+ # def memoized_method
+ # strong_memoize(:memoized_method) do
+ # 'This is a memoized method'
+ # end
+ # end
+ #
+ # Very bad, can't be autocorrected:
+ #
+ # def memoized_method
+ # return unless enabled?
+ #
+ # strong_memoize(:memoized_method) do
+ # 'This is a memoized method'
+ # end
+ # end
+ #
class StrongMemoizeAttr < RuboCop::Cop::Base
extend RuboCop::Cop::AutoCorrector
MSG = 'Use `strong_memoize_attr`, instead of using `strong_memoize` directly'
def_node_matcher :strong_memoize?, <<~PATTERN
- (def $_ _
- (block
- $(send nil? :strong_memoize
- (sym $_)
- )
- (args)
- $_
+ (block
+ $(send nil? :strong_memoize
+ (sym $_)
)
+ (args)
+ $_
)
PATTERN
- def on_def(node)
- method_name, send_node, attr_name, body = strong_memoize?(node)
- return unless method_name
+ def on_block(node)
+ send_node, attr_name, body = strong_memoize?(node)
+ return unless send_node
- add_offense(send_node) do |corrector|
+ corrector = autocorrect_pure_definitions(node.parent, attr_name, body) if node.parent.def_type?
+
+ add_offense(send_node, &corrector)
+ end
+
+ private
+
+ def autocorrect_pure_definitions(def_node, attr_name, body)
+ proc do |corrector|
+ method_name = def_node.method_name
attr_suffix = ", :#{attr_name}" if attr_name != method_name
+ replacement = "\n#{indent(def_node)}strong_memoize_attr :#{method_name}#{attr_suffix}"
- corrector.insert_after(node, "\n#{indent(node)}strong_memoize_attr :#{method_name}#{attr_suffix}")
- corrector.replace(node.body, body.source)
+ corrector.insert_after(def_node, replacement)
+ corrector.replace(def_node.body, body.source)
end
end
end
diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/link_dependencies_spec.js b/spec/frontend/vue_shared/components/source_viewer/plugins/link_dependencies_spec.js
index a7b55d7332f..4d38e8ef25d 100644
--- a/spec/frontend/vue_shared/components/source_viewer/plugins/link_dependencies_spec.js
+++ b/spec/frontend/vue_shared/components/source_viewer/plugins/link_dependencies_spec.js
@@ -4,15 +4,16 @@ import gemspecLinker from '~/vue_shared/components/source_viewer/plugins/utils/g
import gemfileLinker from '~/vue_shared/components/source_viewer/plugins/utils/gemfile_linker';
import podspecJsonLinker from '~/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker';
import composerJsonLinker from '~/vue_shared/components/source_viewer/plugins/utils/composer_json_linker';
+import goSumLinker from '~/vue_shared/components/source_viewer/plugins/utils/go_sum_linker';
import linkDependencies from '~/vue_shared/components/source_viewer/plugins/link_dependencies';
import {
PACKAGE_JSON_FILE_TYPE,
- PACKAGE_JSON_CONTENT,
GEMSPEC_FILE_TYPE,
GODEPS_JSON_FILE_TYPE,
GEMFILE_FILE_TYPE,
PODSPEC_JSON_FILE_TYPE,
COMPOSER_JSON_FILE_TYPE,
+ GO_SUM_FILE_TYPE,
} from './mock_data';
jest.mock('~/vue_shared/components/source_viewer/plugins/utils/package_json_linker');
@@ -21,37 +22,31 @@ jest.mock('~/vue_shared/components/source_viewer/plugins/utils/godeps_json_linke
jest.mock('~/vue_shared/components/source_viewer/plugins/utils/gemfile_linker');
jest.mock('~/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker');
jest.mock('~/vue_shared/components/source_viewer/plugins/utils/composer_json_linker');
+jest.mock('~/vue_shared/components/source_viewer/plugins/utils/go_sum_linker');
describe('Highlight.js plugin for linking dependencies', () => {
const hljsResultMock = { value: 'test' };
- it('calls packageJsonLinker for package_json file types', () => {
- linkDependencies(hljsResultMock, PACKAGE_JSON_FILE_TYPE, PACKAGE_JSON_CONTENT);
- expect(packageJsonLinker).toHaveBeenCalled();
- });
-
- it('calls gemspecLinker for gemspec file types', () => {
- linkDependencies(hljsResultMock, GEMSPEC_FILE_TYPE);
- expect(gemspecLinker).toHaveBeenCalled();
- });
-
- it('calls godepsJsonLinker for godeps_json file types', () => {
- linkDependencies(hljsResultMock, GODEPS_JSON_FILE_TYPE);
- expect(godepsJsonLinker).toHaveBeenCalled();
- });
-
- it('calls gemfileLinker for gemfile file types', () => {
- linkDependencies(hljsResultMock, GEMFILE_FILE_TYPE);
- expect(gemfileLinker).toHaveBeenCalled();
- });
-
- it('calls podspecJsonLinker for podspec_json file types', () => {
- linkDependencies(hljsResultMock, PODSPEC_JSON_FILE_TYPE);
- expect(podspecJsonLinker).toHaveBeenCalled();
- });
-
- it('calls composerJsonLinker for composer_json file types', () => {
- linkDependencies(hljsResultMock, COMPOSER_JSON_FILE_TYPE);
- expect(composerJsonLinker).toHaveBeenCalled();
+ describe.each`
+ fileType | linker
+ ${PACKAGE_JSON_FILE_TYPE} | ${packageJsonLinker}
+ ${GEMSPEC_FILE_TYPE} | ${gemspecLinker}
+ ${GODEPS_JSON_FILE_TYPE} | ${godepsJsonLinker}
+ ${GEMFILE_FILE_TYPE} | ${gemfileLinker}
+ ${PODSPEC_JSON_FILE_TYPE} | ${podspecJsonLinker}
+ ${COMPOSER_JSON_FILE_TYPE} | ${composerJsonLinker}
+ ${GO_SUM_FILE_TYPE} | ${goSumLinker}
+ `('$fileType file type', ({ fileType, linker }) => {
+ it('calls the correct linker', () => {
+ linkDependencies(hljsResultMock, fileType);
+ expect(linker).toHaveBeenCalled();
+ });
+
+ it('does not call the linker for non-matching file types', () => {
+ const unknownFileType = 'unknown';
+
+ linkDependencies(hljsResultMock, unknownFileType);
+ expect(linker).not.toHaveBeenCalled();
+ });
});
});
diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/mock_data.js b/spec/frontend/vue_shared/components/source_viewer/plugins/mock_data.js
index 5455479ec71..631baf19a2d 100644
--- a/spec/frontend/vue_shared/components/source_viewer/plugins/mock_data.js
+++ b/spec/frontend/vue_shared/components/source_viewer/plugins/mock_data.js
@@ -32,3 +32,5 @@ export const PODSPEC_JSON_CONTENT = `{
}`;
export const COMPOSER_JSON_FILE_TYPE = 'composer_json';
+
+export const GO_SUM_FILE_TYPE = 'go_sum';
diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/utils/go_sum_linker_spec.js b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/go_sum_linker_spec.js
new file mode 100644
index 00000000000..293396c9de7
--- /dev/null
+++ b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/go_sum_linker_spec.js
@@ -0,0 +1,14 @@
+import goSumLinker from '~/vue_shared/components/source_viewer/plugins/utils/go_sum_linker';
+
+describe('Highlight.js plugin for linking go.sum dependencies', () => {
+ it('mutates the input value by wrapping dependencies and tags in anchors', () => {
+ const inputValue =
+ '<span class="">cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=</span>';
+ const outputValue =
+ '<span class=""><a href="https://pkg.go.dev/cloud.google.com/go/bigquery" target="_blank" rel="nofollow noreferrer noopener">cloud.google.com/go/bigquery</a> v1.0.1/go.mod h1:<a href="https://sum.golang.org/lookup/cloud.google.com/go/bigquery@v1.0.1" target="_blank" rel="nofollow noreferrer noopener">i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=</a></span>';
+ const hljsResultMock = { value: inputValue };
+
+ const output = goSumLinker(hljsResultMock);
+ expect(output).toBe(outputValue);
+ });
+});
diff --git a/spec/lib/gitlab/data_builder/deployment_spec.rb b/spec/lib/gitlab/data_builder/deployment_spec.rb
index 8ee57542d43..bf08e782035 100644
--- a/spec/lib/gitlab/data_builder/deployment_spec.rb
+++ b/spec/lib/gitlab/data_builder/deployment_spec.rb
@@ -12,8 +12,8 @@ RSpec.describe Gitlab::DataBuilder::Deployment do
expect(data[:object_kind]).to eq('deployment')
end
- it 'returns data for the given build' do
- environment = create(:environment, name: "somewhere")
+ it 'returns data for the given build', :aggregate_failures do
+ environment = create(:environment, name: 'somewhere/1', external_url: 'https://test.com')
project = create(:project, :repository, name: 'myproj')
commit = project.commit('HEAD')
deployment = create(:deployment, status: :failed, environment: environment, sha: commit.sha, project: project)
@@ -30,7 +30,9 @@ RSpec.describe Gitlab::DataBuilder::Deployment do
expect(data[:deployment_id]).to eq(deployment.id)
expect(data[:deployable_id]).to eq(deployable.id)
expect(data[:deployable_url]).to eq(expected_deployable_url)
- expect(data[:environment]).to eq("somewhere")
+ expect(data[:environment]).to eq('somewhere/1')
+ expect(data[:environment_slug]).to eq('somewhere-1-78avk6')
+ expect(data[:environment_external_url]).to eq('https://test.com')
expect(data[:project]).to eq(project.hook_attrs)
expect(data[:short_sha]).to eq(deployment.short_sha)
expect(data[:user]).to eq(deployment.deployed_by.hook_attrs)
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index 7a9b8f3ccc1..918b091eef2 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -44,7 +44,6 @@ RSpec.describe Gitlab::Workhorse do
expect(params).to eq({
'GitalyServer' => {
'call_metadata' => features,
- 'features' => features,
address: Gitlab::GitalyClient.address(project.repository_storage),
token: Gitlab::GitalyClient.token(project.repository_storage)
},
@@ -95,7 +94,6 @@ RSpec.describe Gitlab::Workhorse do
expect(params).to eq({
'GitalyServer' => {
'call_metadata' => features,
- 'features' => features,
address: Gitlab::GitalyClient.address(project.repository_storage),
token: Gitlab::GitalyClient.token(project.repository_storage)
},
@@ -159,7 +157,6 @@ RSpec.describe Gitlab::Workhorse do
expect(params).to eq({
'GitalyServer' => {
'call_metadata' => features,
- 'features' => features,
address: Gitlab::GitalyClient.address(project.repository_storage),
token: Gitlab::GitalyClient.token(project.repository_storage)
},
@@ -254,7 +251,6 @@ RSpec.describe Gitlab::Workhorse do
{
GitalyServer: {
call_metadata: call_metadata,
- features: features,
address: Gitlab::GitalyClient.address('default'),
token: Gitlab::GitalyClient.token('default')
}
@@ -299,24 +295,24 @@ RSpec.describe Gitlab::Workhorse do
it 'sets the flag to true for that project' do
response = described_class.git_http_ok(repository, Gitlab::GlRepository::PROJECT, user, action)
- expect(response.dig(:GitalyServer, :features)).to eq('gitaly-feature-enforce-requests-limits' => 'true',
- 'gitaly-feature-mep-mep' => 'true')
+ expect(response.dig(:GitalyServer, :call_metadata)).to include('gitaly-feature-enforce-requests-limits' => 'true',
+ 'gitaly-feature-mep-mep' => 'true')
end
it 'sets the flag to false for other projects' do
other_project = create(:project, :public, :repository)
response = described_class.git_http_ok(other_project.repository, Gitlab::GlRepository::PROJECT, user, action)
- expect(response.dig(:GitalyServer, :features)).to eq('gitaly-feature-enforce-requests-limits' => 'true',
- 'gitaly-feature-mep-mep' => 'false')
+ expect(response.dig(:GitalyServer, :call_metadata)).to include('gitaly-feature-enforce-requests-limits' => 'true',
+ 'gitaly-feature-mep-mep' => 'false')
end
it 'sets the flag to false when there is no project' do
snippet = create(:personal_snippet, :repository)
response = described_class.git_http_ok(snippet.repository, Gitlab::GlRepository::SNIPPET, user, action)
- expect(response.dig(:GitalyServer, :features)).to eq('gitaly-feature-enforce-requests-limits' => 'true',
- 'gitaly-feature-mep-mep' => 'false')
+ expect(response.dig(:GitalyServer, :call_metadata)).to include('gitaly-feature-enforce-requests-limits' => 'true',
+ 'gitaly-feature-mep-mep' => 'false')
end
end
end
@@ -368,7 +364,6 @@ RSpec.describe Gitlab::Workhorse do
Gitlab::ApplicationContext.with_context(remote_ip: "1.2.3.4") do
result = described_class.git_http_ok(repository, Gitlab::GlRepository::PROJECT, user, action)
end
- expect(result[:RemoteIP]).to eql("1.2.3.4")
expect(result[:GitalyServer][:call_metadata]['remote_ip']).to eql("1.2.3.4")
end
end
@@ -376,7 +371,6 @@ RSpec.describe Gitlab::Workhorse do
context 'when remote_ip is not available in the application context' do
it 'does not include RemoteIP params' do
result = described_class.git_http_ok(repository, Gitlab::GlRepository::PROJECT, user, action)
- expect(result).not_to have_key(:RemoteIP)
expect(result[:GitalyServer][:call_metadata]).not_to have_key('remote_ip')
end
end
@@ -460,7 +454,6 @@ RSpec.describe Gitlab::Workhorse do
expect(params).to eq({
'GitalyServer' => {
'call_metadata' => features,
- 'features' => features,
address: Gitlab::GitalyClient.address(project.repository_storage),
token: Gitlab::GitalyClient.token(project.repository_storage)
},
@@ -541,7 +534,6 @@ RSpec.describe Gitlab::Workhorse do
expect(params).to eq(
'GitalyServer' => {
'call_metadata' => features,
- 'features' => features,
'address' => Gitlab::GitalyClient.address(project.repository_storage),
'token' => Gitlab::GitalyClient.token(project.repository_storage)
},
diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb
index fcbb4b97a75..df24c92149d 100644
--- a/spec/models/ci/bridge_spec.rb
+++ b/spec/models/ci/bridge_spec.rb
@@ -21,8 +21,8 @@ RSpec.describe Ci::Bridge do
{ trigger: { project: 'my/project', branch: 'master' } }
end
- it 'has one sourced pipeline' do
- expect(bridge).to have_one(:sourced_pipeline)
+ it 'has many sourced pipelines' do
+ expect(bridge).to have_many(:sourced_pipelines)
end
it_behaves_like 'has ID tokens', :ci_bridge
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 52d35f6d79d..3585fda78c3 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -24,6 +24,7 @@ RSpec.describe Ci::Build do
it { is_expected.to belong_to(:erased_by) }
it { is_expected.to have_many(:needs) }
+ it { is_expected.to have_many(:sourced_pipelines) }
it { is_expected.to have_one(:sourced_pipeline) }
it { is_expected.to have_many(:job_variables) }
it { is_expected.to have_many(:report_results) }
diff --git a/spec/models/ci/processable_spec.rb b/spec/models/ci/processable_spec.rb
index 004716fffc4..e62e5f84a6d 100644
--- a/spec/models/ci/processable_spec.rb
+++ b/spec/models/ci/processable_spec.rb
@@ -81,7 +81,7 @@ RSpec.describe Ci::Processable do
commit_id deployment erased_by_id project_id
runner_id tag_taggings taggings tags trigger_request_id
user_id auto_canceled_by_id retried failure_reason
- sourced_pipeline artifacts_file_store artifacts_metadata_store
+ sourced_pipelines sourced_pipeline artifacts_file_store artifacts_metadata_store
metadata runner_session trace_chunks upstream_pipeline_id
artifacts_file artifacts_metadata artifacts_size commands
resource resource_group_id processed security_scans author
diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb
index 68c284a913c..2ece04c7158 100644
--- a/spec/models/hooks/service_hook_spec.rb
+++ b/spec/models/hooks/service_hook_spec.rb
@@ -11,6 +11,32 @@ RSpec.describe ServiceHook do
it { is_expected.to validate_presence_of(:integration) }
end
+ describe 'executable?' do
+ let!(:hooks) do
+ [
+ [0, Time.current],
+ [0, 1.minute.from_now],
+ [1, 1.minute.from_now],
+ [3, 1.minute.from_now],
+ [4, nil],
+ [4, 1.day.ago],
+ [4, 1.minute.from_now],
+ [0, nil],
+ [0, 1.day.ago],
+ [1, nil],
+ [1, 1.day.ago],
+ [3, nil],
+ [3, 1.day.ago]
+ ].map do |(recent_failures, disabled_until)|
+ create(:service_hook, recent_failures: recent_failures, disabled_until: disabled_until)
+ end
+ end
+
+ it 'is always true' do
+ expect(hooks).to all(be_executable)
+ end
+ end
+
describe 'execute' do
let(:hook) { build(:service_hook) }
let(:data) { { key: 'value' } }
diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml
index 2ff4cd72f1e..da478a3547e 100644
--- a/spec/requests/api/project_attributes.yml
+++ b/spec/requests/api/project_attributes.yml
@@ -43,6 +43,7 @@ itself: # project
- storage_version
- topic_list
- updated_at
+ - mirror_branch_regex
remapped_attributes:
avatar: avatar_url
build_allow_git_fetch: build_git_strategy
diff --git a/spec/requests/api/project_snapshots_spec.rb b/spec/requests/api/project_snapshots_spec.rb
index 954091635a1..5a06800c8f6 100644
--- a/spec/requests/api/project_snapshots_spec.rb
+++ b/spec/requests/api/project_snapshots_spec.rb
@@ -7,7 +7,6 @@ RSpec.describe API::ProjectSnapshots do
let(:project) { create(:project) }
let(:admin) { create(:admin) }
- let(:features) { { 'gitaly-feature-foobar' => 'true' } }
before do
allow(Feature::Gitaly).to receive(:server_feature_flags).and_return({
@@ -22,8 +21,7 @@ RSpec.describe API::ProjectSnapshots do
expect(type).to eq('git-snapshot')
expect(params).to eq(
'GitalyServer' => {
- 'call_metadata' => features,
- 'features' => features,
+ 'call_metadata' => { 'gitaly-feature-foobar' => 'true' },
'address' => Gitlab::GitalyClient.address(repository.project.repository_storage),
'token' => Gitlab::GitalyClient.token(repository.project.repository_storage)
},
diff --git a/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb b/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb
index 20dd0f89f53..0ed699f4e8c 100644
--- a/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb
+++ b/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb
@@ -55,18 +55,21 @@ RSpec.describe RuboCop::Cop::Gitlab::StrongMemoizeAttr do
end
context 'when strong_memoize() is not the entire body of the method' do
- it 'does not register an offense or autocorrect' do
- expect_no_offenses(<<~RUBY)
+ it 'registers an offense and does not autocorrect' do
+ expect_offense(<<~RUBY)
class Foo
def memoized_method
msg = 'This is a memoized method'
strong_memoize(:memoized_method) do
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `strong_memoize_attr`, instead of using `strong_memoize` directly
msg
end
end
end
RUBY
+
+ expect_no_corrections
end
end
end
diff --git a/spec/services/ci/create_downstream_pipeline_service_spec.rb b/spec/services/ci/create_downstream_pipeline_service_spec.rb
index 751d976dd10..9c02c5218f1 100644
--- a/spec/services/ci/create_downstream_pipeline_service_spec.rb
+++ b/spec/services/ci/create_downstream_pipeline_service_spec.rb
@@ -110,7 +110,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
expect(pipeline.user).to eq bridge.user
expect(pipeline.project).to eq downstream_project
- expect(bridge.reload.sourced_pipeline.pipeline).to eq pipeline
+ expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline
expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline
expect(pipeline.source_bridge).to eq bridge
expect(pipeline.source_bridge).to be_a ::Ci::Bridge
@@ -131,7 +131,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
context 'when bridge job has already any downstream pipelines' do
before do
- bridge.create_sourced_pipeline!(
+ bridge.sourced_pipelines.create!(
source_pipeline: bridge.pipeline,
source_project: bridge.project,
project: bridge.project,
@@ -178,7 +178,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
expect(pipeline.user).to eq bridge.user
expect(pipeline.project).to eq downstream_project
- expect(bridge.reload.sourced_pipeline.pipeline).to eq pipeline
+ expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline
expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline
expect(pipeline.source_bridge).to eq bridge
expect(pipeline.source_bridge).to be_a ::Ci::Bridge
@@ -231,7 +231,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
expect(pipeline.builds.map(&:name)).to match_array(%w[rspec echo])
expect(pipeline.user).to eq bridge.user
expect(pipeline.project).to eq bridge.project
- expect(bridge.reload.sourced_pipeline.pipeline).to eq pipeline
+ expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline
expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline
expect(pipeline.source_bridge).to eq bridge
expect(pipeline.source_bridge).to be_a ::Ci::Bridge
diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb
index d8ea546742b..4b3e774ff3c 100644
--- a/spec/services/ci/pipeline_trigger_service_spec.rb
+++ b/spec/services/ci/pipeline_trigger_service_spec.rb
@@ -225,7 +225,7 @@ RSpec.describe Ci::PipelineTriggerService do
expect { result }.to change { Ci::PipelineVariable.count }.by(2)
.and change { Ci::Sources::Pipeline.count }.by(1)
expect(result[:pipeline].variables.map { |v| { v.key => v.value } }.first).to eq(variables)
- expect(job.sourced_pipeline.pipeline_id).to eq(result[:pipeline].id)
+ expect(job.sourced_pipelines.last.pipeline_id).to eq(result[:pipeline].id)
end
end
diff --git a/workhorse/gitaly_integration_test.go b/workhorse/gitaly_integration_test.go
index a2826c3edc4..ed44aaddbc3 100644
--- a/workhorse/gitaly_integration_test.go
+++ b/workhorse/gitaly_integration_test.go
@@ -58,7 +58,6 @@ func ensureGitalyRepository(t *testing.T, apiResponse *api.Response) error {
ctx, namespace, err := gitaly.NewNamespaceClient(
context.Background(),
apiResponse.GitalyServer,
- gitaly.WithFeatures(apiResponse.GitalyServer.Features),
)
if err != nil {
diff --git a/workhorse/gitaly_test.go b/workhorse/gitaly_test.go
index b9cf4fcc685..2d7f727003f 100644
--- a/workhorse/gitaly_test.go
+++ b/workhorse/gitaly_test.go
@@ -78,7 +78,7 @@ func TestGetInfoRefsProxiedToGitalySuccessfully(t *testing.T) {
for k, v := range badMetadata {
features[k] = v
}
- apiResponse.GitalyServer.Features = features
+ apiResponse.GitalyServer.CallMetadata = features
testCases := []struct {
showAllRefs bool
@@ -272,7 +272,6 @@ func TestPostReceivePackProxiedToGitalySuccessfully(t *testing.T) {
require.Equal(t, apiResponse.Repository.RelativePath, gitalyRequest.Repository.RelativePath)
require.Equal(t, apiResponse.GL_ID, gitalyRequest.GlId)
require.Equal(t, apiResponse.GL_USERNAME, gitalyRequest.GlUsername)
- require.Equal(t, apiResponse.RemoteIp, "1.2.3.4")
require.Equal(t, apiResponse.GitConfigOptions, gitalyRequest.GitConfigOptions)
require.Equal(t, gitProtocol, gitalyRequest.GitProtocol)
diff --git a/workhorse/internal/api/api.go b/workhorse/internal/api/api.go
index ba27a3e6ec9..011890be569 100644
--- a/workhorse/internal/api/api.go
+++ b/workhorse/internal/api/api.go
@@ -129,9 +129,6 @@ type Response struct {
// 'git push' and 'git pull'
GL_REPOSITORY string
- // RemoteIp holds the IP of the request issuing the action
- RemoteIp string
-
// GitConfigOptions holds the custom options that we want to pass to the git command
GitConfigOptions []string
// StoreLFSPath is provided by the GitLab Rails application to mark where the tmp file should be placed.
@@ -166,9 +163,9 @@ type Response struct {
}
type GitalyServer struct {
- Address string `json:"address"`
- Token string `json:"token"`
- Features map[string]string `json:"features"`
+ Address string `json:"address"`
+ Token string `json:"token"`
+ CallMetadata map[string]string `json:"call_metadata"`
}
// singleJoiningSlash is taken from reverseproxy.go:singleJoiningSlash
diff --git a/workhorse/internal/git/archive.go b/workhorse/internal/git/archive.go
index 4c7b519310f..5c6bc2e2266 100644
--- a/workhorse/internal/git/archive.go
+++ b/workhorse/internal/git/archive.go
@@ -132,11 +132,7 @@ func (a *archive) Inject(w http.ResponseWriter, r *http.Request, sendData string
func handleArchiveWithGitaly(r *http.Request, params *archiveParams, format gitalypb.GetArchiveRequest_Format) (io.Reader, error) {
var request *gitalypb.GetArchiveRequest
- ctx, c, err := gitaly.NewRepositoryClient(
- r.Context(),
- params.GitalyServer,
- gitaly.WithFeatures(params.GitalyServer.Features),
- )
+ ctx, c, err := gitaly.NewRepositoryClient(r.Context(), params.GitalyServer)
if err != nil {
return nil, err
diff --git a/workhorse/internal/git/blob.go b/workhorse/internal/git/blob.go
index 39bd4490e66..a6d9cd8b1da 100644
--- a/workhorse/internal/git/blob.go
+++ b/workhorse/internal/git/blob.go
@@ -27,11 +27,7 @@ func (b *blob) Inject(w http.ResponseWriter, r *http.Request, sendData string) {
return
}
- ctx, blobClient, err := gitaly.NewBlobClient(
- r.Context(),
- params.GitalyServer,
- gitaly.WithFeatures(params.GitalyServer.Features),
- )
+ ctx, blobClient, err := gitaly.NewBlobClient(r.Context(), params.GitalyServer)
if err != nil {
helper.Fail500(w, r, fmt.Errorf("blob.GetBlob: %v", err))
diff --git a/workhorse/internal/git/diff.go b/workhorse/internal/git/diff.go
index b4878384e2b..9ae95bb6680 100644
--- a/workhorse/internal/git/diff.go
+++ b/workhorse/internal/git/diff.go
@@ -34,11 +34,7 @@ func (d *diff) Inject(w http.ResponseWriter, r *http.Request, sendData string) {
return
}
- ctx, diffClient, err := gitaly.NewDiffClient(
- r.Context(),
- params.GitalyServer,
- gitaly.WithFeatures(params.GitalyServer.Features),
- )
+ ctx, diffClient, err := gitaly.NewDiffClient(r.Context(), params.GitalyServer)
if err != nil {
helper.Fail500(w, r, fmt.Errorf("diff.RawDiff: %v", err))
return
diff --git a/workhorse/internal/git/format-patch.go b/workhorse/internal/git/format-patch.go
index 264a4001232..d0b2e875c95 100644
--- a/workhorse/internal/git/format-patch.go
+++ b/workhorse/internal/git/format-patch.go
@@ -34,11 +34,7 @@ func (p *patch) Inject(w http.ResponseWriter, r *http.Request, sendData string)
return
}
- ctx, diffClient, err := gitaly.NewDiffClient(
- r.Context(),
- params.GitalyServer,
- gitaly.WithFeatures(params.GitalyServer.Features),
- )
+ ctx, diffClient, err := gitaly.NewDiffClient(r.Context(), params.GitalyServer)
if err != nil {
helper.Fail500(w, r, fmt.Errorf("diff.RawPatch: %v", err))
diff --git a/workhorse/internal/git/info-refs.go b/workhorse/internal/git/info-refs.go
index 89db2954e30..b7f825839f8 100644
--- a/workhorse/internal/git/info-refs.go
+++ b/workhorse/internal/git/info-refs.go
@@ -55,12 +55,7 @@ func handleGetInfoRefs(rw http.ResponseWriter, r *http.Request, a *api.Response)
}
func handleGetInfoRefsWithGitaly(ctx context.Context, responseWriter *HttpResponseWriter, a *api.Response, rpc, gitProtocol, encoding string) error {
- ctx, smarthttp, err := gitaly.NewSmartHTTPClient(
- ctx,
- a.GitalyServer,
- gitaly.WithFeatures(a.GitalyServer.Features),
- gitaly.WithLoggingMetadata(a),
- )
+ ctx, smarthttp, err := gitaly.NewSmartHTTPClient(ctx, a.GitalyServer)
if err != nil {
return err
}
diff --git a/workhorse/internal/git/receive-pack.go b/workhorse/internal/git/receive-pack.go
index b312bbad621..e3af472fffa 100644
--- a/workhorse/internal/git/receive-pack.go
+++ b/workhorse/internal/git/receive-pack.go
@@ -20,12 +20,7 @@ func handleReceivePack(w *HttpResponseWriter, r *http.Request, a *api.Response)
gitProtocol := r.Header.Get("Git-Protocol")
- ctx, smarthttp, err := gitaly.NewSmartHTTPClient(
- r.Context(),
- a.GitalyServer,
- gitaly.WithFeatures(a.GitalyServer.Features),
- gitaly.WithLoggingMetadata(a),
- )
+ ctx, smarthttp, err := gitaly.NewSmartHTTPClient(r.Context(), a.GitalyServer)
if err != nil {
return fmt.Errorf("smarthttp.ReceivePack: %v", err)
}
diff --git a/workhorse/internal/git/snapshot.go b/workhorse/internal/git/snapshot.go
index 70832ec9211..aadb35a5189 100644
--- a/workhorse/internal/git/snapshot.go
+++ b/workhorse/internal/git/snapshot.go
@@ -41,11 +41,7 @@ func (s *snapshot) Inject(w http.ResponseWriter, r *http.Request, sendData strin
return
}
- ctx, c, err := gitaly.NewRepositoryClient(
- r.Context(),
- params.GitalyServer,
- gitaly.WithFeatures(params.GitalyServer.Features),
- )
+ ctx, c, err := gitaly.NewRepositoryClient(r.Context(), params.GitalyServer)
if err != nil {
helper.Fail500(w, r, fmt.Errorf("SendSnapshot: gitaly.NewRepositoryClient: %v", err))
diff --git a/workhorse/internal/git/upload-pack.go b/workhorse/internal/git/upload-pack.go
index 13c0069cde2..74995fb61c8 100644
--- a/workhorse/internal/git/upload-pack.go
+++ b/workhorse/internal/git/upload-pack.go
@@ -44,12 +44,7 @@ func handleUploadPack(w *HttpResponseWriter, r *http.Request, a *api.Response) e
}
func handleUploadPackWithGitaly(ctx context.Context, a *api.Response, clientRequest io.Reader, clientResponse io.Writer, gitProtocol string) error {
- ctx, smarthttp, err := gitaly.NewSmartHTTPClient(
- ctx,
- a.GitalyServer,
- gitaly.WithFeatures(a.GitalyServer.Features),
- gitaly.WithLoggingMetadata(a),
- )
+ ctx, smarthttp, err := gitaly.NewSmartHTTPClient(ctx, a.GitalyServer)
if err != nil {
return fmt.Errorf("get gitaly client: %w", err)
}
diff --git a/workhorse/internal/gitaly/gitaly.go b/workhorse/internal/gitaly/gitaly.go
index 799159689ae..af7425be1cf 100644
--- a/workhorse/internal/gitaly/gitaly.go
+++ b/workhorse/internal/gitaly/gitaly.go
@@ -67,44 +67,23 @@ func InitializeSidechannelRegistry(logger *logrus.Logger) {
}
}
-type MetadataFunc func(metadata.MD)
-
-func WithFeatures(features map[string]string) MetadataFunc {
- return func(md metadata.MD) {
- for k, v := range features {
- if !strings.HasPrefix(k, "gitaly-feature-") {
- continue
- }
- md.Append(k, v)
- }
- }
-}
-
-func WithLoggingMetadata(r *api.Response) MetadataFunc {
- return func(md metadata.MD) {
- if r.GL_ID != "" {
- md.Append("user_id", r.GL_ID)
- }
- if r.GL_USERNAME != "" {
- md.Append("username", r.GL_USERNAME)
- }
- if r.RemoteIp != "" {
- md.Append("remote_ip", r.RemoteIp)
- }
- }
+var allowedMetadataKeys = map[string]bool{
+ "user_id": true,
+ "username": true,
+ "remote_ip": true,
}
-func withOutgoingMetadata(ctx context.Context, addMetadataFuncs ...MetadataFunc) context.Context {
+func withOutgoingMetadata(ctx context.Context, gs api.GitalyServer) context.Context {
md := metadata.New(nil)
-
- for _, f := range addMetadataFuncs {
- f(md)
+ for k, v := range gs.CallMetadata {
+ if strings.HasPrefix(k, "gitaly-feature-") || allowedMetadataKeys[k] {
+ md.Set(k, v)
+ }
}
-
return metadata.NewOutgoingContext(ctx, md)
}
-func NewSmartHTTPClient(ctx context.Context, server api.GitalyServer, metadataFuncs ...MetadataFunc) (context.Context, *SmartHTTPClient, error) {
+func NewSmartHTTPClient(ctx context.Context, server api.GitalyServer) (context.Context, *SmartHTTPClient, error) {
conn, err := getOrCreateConnection(server)
if err != nil {
return nil, nil, err
@@ -114,48 +93,44 @@ func NewSmartHTTPClient(ctx context.Context, server api.GitalyServer, metadataFu
SmartHTTPServiceClient: grpcClient,
sidechannelRegistry: sidechannelRegistry,
}
-
- return withOutgoingMetadata(
- ctx,
- metadataFuncs...,
- ), smartHTTPClient, nil
+ return withOutgoingMetadata(ctx, server), smartHTTPClient, nil
}
-func NewBlobClient(ctx context.Context, server api.GitalyServer, addMetadataFuncs ...MetadataFunc) (context.Context, *BlobClient, error) {
+func NewBlobClient(ctx context.Context, server api.GitalyServer) (context.Context, *BlobClient, error) {
conn, err := getOrCreateConnection(server)
if err != nil {
return nil, nil, err
}
grpcClient := gitalypb.NewBlobServiceClient(conn)
- return withOutgoingMetadata(ctx, addMetadataFuncs...), &BlobClient{grpcClient}, nil
+ return withOutgoingMetadata(ctx, server), &BlobClient{grpcClient}, nil
}
-func NewRepositoryClient(ctx context.Context, server api.GitalyServer, addMetadataFuncs ...MetadataFunc) (context.Context, *RepositoryClient, error) {
+func NewRepositoryClient(ctx context.Context, server api.GitalyServer) (context.Context, *RepositoryClient, error) {
conn, err := getOrCreateConnection(server)
if err != nil {
return nil, nil, err
}
grpcClient := gitalypb.NewRepositoryServiceClient(conn)
- return withOutgoingMetadata(ctx, addMetadataFuncs...), &RepositoryClient{grpcClient}, nil
+ return withOutgoingMetadata(ctx, server), &RepositoryClient{grpcClient}, nil
}
// NewNamespaceClient is only used by the Gitaly integration tests at present
-func NewNamespaceClient(ctx context.Context, server api.GitalyServer, addMetadataFuncs ...MetadataFunc) (context.Context, *NamespaceClient, error) {
+func NewNamespaceClient(ctx context.Context, server api.GitalyServer) (context.Context, *NamespaceClient, error) {
conn, err := getOrCreateConnection(server)
if err != nil {
return nil, nil, err
}
grpcClient := gitalypb.NewNamespaceServiceClient(conn)
- return withOutgoingMetadata(ctx, addMetadataFuncs...), &NamespaceClient{grpcClient}, nil
+ return withOutgoingMetadata(ctx, server), &NamespaceClient{grpcClient}, nil
}
-func NewDiffClient(ctx context.Context, server api.GitalyServer, addMetadataFuncs ...MetadataFunc) (context.Context, *DiffClient, error) {
+func NewDiffClient(ctx context.Context, server api.GitalyServer) (context.Context, *DiffClient, error) {
conn, err := getOrCreateConnection(server)
if err != nil {
return nil, nil, err
}
grpcClient := gitalypb.NewDiffServiceClient(conn)
- return withOutgoingMetadata(ctx, addMetadataFuncs...), &DiffClient{grpcClient}, nil
+ return withOutgoingMetadata(ctx, server), &DiffClient{grpcClient}, nil
}
func getOrCreateConnection(server api.GitalyServer) (*grpc.ClientConn, error) {
diff --git a/workhorse/internal/gitaly/gitaly_test.go b/workhorse/internal/gitaly/gitaly_test.go
index f81dc16149a..0ea5da20da3 100644
--- a/workhorse/internal/gitaly/gitaly_test.go
+++ b/workhorse/internal/gitaly/gitaly_test.go
@@ -21,17 +21,9 @@ func TestNewSmartHTTPClient(t *testing.T) {
ctx, client, err := NewSmartHTTPClient(
context.Background(),
serverFixture(),
- WithFeatures(features()),
- WithLoggingMetadata(&api.Response{
- GL_USERNAME: "gl_username",
- GL_ID: "gl_id",
- RemoteIp: "1.2.3.4",
- }),
)
require.NoError(t, err)
testOutgoingMetadata(t, ctx)
- testOutgoingIDAndUsername(t, ctx)
- testOutgoingRemoteIP(t, ctx)
require.NotNil(t, client.sidechannelRegistry)
}
@@ -39,7 +31,6 @@ func TestNewBlobClient(t *testing.T) {
ctx, _, err := NewBlobClient(
context.Background(),
serverFixture(),
- WithFeatures(features()),
)
require.NoError(t, err)
testOutgoingMetadata(t, ctx)
@@ -49,7 +40,6 @@ func TestNewRepositoryClient(t *testing.T) {
ctx, _, err := NewRepositoryClient(
context.Background(),
serverFixture(),
- WithFeatures(features()),
)
require.NoError(t, err)
@@ -60,7 +50,6 @@ func TestNewNamespaceClient(t *testing.T) {
ctx, _, err := NewNamespaceClient(
context.Background(),
serverFixture(),
- WithFeatures(features()),
)
require.NoError(t, err)
testOutgoingMetadata(t, ctx)
@@ -70,69 +59,45 @@ func TestNewDiffClient(t *testing.T) {
ctx, _, err := NewDiffClient(
context.Background(),
serverFixture(),
- WithFeatures(features()),
)
require.NoError(t, err)
testOutgoingMetadata(t, ctx)
}
func testOutgoingMetadata(t *testing.T, ctx context.Context) {
+ t.Helper()
md, ok := metadata.FromOutgoingContext(ctx)
require.True(t, ok, "get metadata from context")
- for k, v := range allowedFeatures() {
- actual := md[k]
- require.Len(t, actual, 1, "expect one value for %v", k)
- require.Equal(t, v, actual[0], "value for %v", k)
- }
-
- for k := range badFeatureMetadata() {
- require.Empty(t, md[k], "value for bad key %v", k)
- }
-}
-
-func testOutgoingIDAndUsername(t *testing.T, ctx context.Context) {
- md, ok := metadata.FromOutgoingContext(ctx)
- require.True(t, ok, "get metadata from context")
-
- require.Equal(t, md["user_id"], []string{"gl_id"})
- require.Equal(t, md["username"], []string{"gl_username"})
-}
-
-func testOutgoingRemoteIP(t *testing.T, ctx context.Context) {
- md, ok := metadata.FromOutgoingContext(ctx)
- require.True(t, ok, "get metadata from context")
-
- require.Equal(t, md["remote_ip"], []string{"1.2.3.4"})
-}
-
-func features() map[string]string {
- features := make(map[string]string)
- for k, v := range allowedFeatures() {
- features[k] = v
- }
-
- for k, v := range badFeatureMetadata() {
- features[k] = v
- }
-
- return features
+ require.Equal(t, metadata.MD{"username": {"janedoe"}}, md)
}
func serverFixture() api.GitalyServer {
- return api.GitalyServer{Address: "tcp://localhost:123"}
-}
-
-func allowedFeatures() map[string]string {
- return map[string]string{
- "gitaly-feature-foo": "bar",
- "gitaly-feature-qux": "baz",
+ return api.GitalyServer{
+ Address: "tcp://localhost:123",
+ CallMetadata: map[string]string{"username": "janedoe"},
}
}
-func badFeatureMetadata() map[string]string {
- return map[string]string{
- "bad-metadata-1": "bad-value-1",
- "bad-metadata-2": "bad-value-2",
- }
+func TestWithOutgoingMetadata(t *testing.T) {
+ ctx := withOutgoingMetadata(context.Background(), api.GitalyServer{
+ CallMetadata: map[string]string{
+ "gitaly-feature-abc": "true",
+ "gitaly-featuregarbage": "blocked",
+ "bad-header": "blocked",
+ "user_id": "234",
+ "username": "janedoe",
+ "remote_ip": "1.2.3.4",
+ },
+ })
+
+ md, ok := metadata.FromOutgoingContext(ctx)
+ require.True(t, ok)
+
+ require.Equal(t, metadata.MD{
+ "gitaly-feature-abc": {"true"},
+ "user_id": {"234"},
+ "username": {"janedoe"},
+ "remote_ip": {"1.2.3.4"},
+ }, md)
}
diff --git a/workhorse/main_test.go b/workhorse/main_test.go
index 8dce3480e0b..5ebc26c7ac7 100644
--- a/workhorse/main_test.go
+++ b/workhorse/main_test.go
@@ -813,7 +813,6 @@ func gitOkBody(t *testing.T) *api.Response {
return &api.Response{
GL_ID: "user-123",
GL_USERNAME: "username",
- RemoteIp: "1.2.3.4",
Repository: gitalypb.Repository{
StorageName: "default",
RelativePath: "foo/bar.git",