diff options
30 files changed, 304 insertions, 125 deletions
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml index 30553026c03..96793b1f5d4 100644 --- a/.gitlab/ci/rails.gitlab-ci.yml +++ b/.gitlab/ci/rails.gitlab-ci.yml @@ -765,46 +765,41 @@ rspec system pg14-as-if-foss clusterwide-db: - .clusterwide-db - .rails:rules:clusterwide-db -.rspec-ee-base-gitlab-duo: - extends: - - .rspec-ee-base-pg14 +rspec-ee unit gitlab-duo-chat pg14: variables: REAL_AI_REQUEST: "true" - -rspec-ee unit gitlab-duo-chat-zeroshot pg14: - extends: - - .rspec-ee-base-gitlab-duo - - .rails:rules:ee-gitlab-duo-chat-optional - script: - - !reference [.base-script, script] - - rspec_paralellized_job "--tag zeroshot_executor" - -rspec-ee unit gitlab-duo-chat-qa-fast pg14: + RSPEC_RETRY_RETRY_COUNT: 0 extends: - - .rspec-ee-base-gitlab-duo - - .rails:rules:ee-gitlab-duo-chat-fast + - .rspec-ee-base-pg14 + - .rails:rules:ee-gitlab-duo-chat-base + parallel: + matrix: + - DUO_RSPEC: ["lib/gitlab/llm/chain/agents/zero_shot/executor_real_requests_spec.rb", "support_specs/helpers/chat_qa_evaluation_helpers_spec.rb"] script: - !reference [.base-script, script] - - bundle exec rspec -Ispec -rspec_helper --color --tag fast_chat_qa_evaluation -- ee/spec/lib/gitlab/llm/chain/agents/zero_shot/qa_evaluation_spec.rb + - bundle exec rspec -Ispec -rspec_helper --failure-exit-code 0 --tag real_ai_request --color -- ee/spec/${DUO_RSPEC} rspec-ee unit gitlab-duo-chat-qa pg14: variables: - QA_EVAL_REPORT_FILENAME: "qa_evaluation_report.md" + REAL_AI_REQUEST: "true" RSPEC_RETRY_RETRY_COUNT: 0 extends: - - .rspec-ee-base-gitlab-duo - - .rails:rules:ee-gitlab-duo-chat-optional + - .rspec-ee-base-pg14 + - .rails:rules:ee-gitlab-duo-chat-base + parallel: + matrix: + - DUO_RSPEC: ["qa_epic_spec.rb", "qa_issue_spec.rb"] script: - !reference [.base-script, script] - source ./scripts/utils.sh - install_gitlab_gem - - bundle exec rspec -Ispec -rspec_helper --failure-exit-code 0 --color --tag chat_qa_evaluation -- ee/spec/lib/gitlab/llm/chain/agents/zero_shot/qa_evaluation_spec.rb + - bundle exec rspec -Ispec -rspec_helper --failure-exit-code 0 --tag real_ai_request --color -- ee/spec/lib/gitlab/llm/chain/agents/zero_shot/${DUO_RSPEC} - ./scripts/duo_chat/reporter.rb artifacts: expire_in: 5d paths: - tmp/duo_chat/qa*.json - - "${QA_EVAL_REPORT_FILENAME}" + - "${DUO_RSPEC}.md" rspec-ee migration pg14: extends: diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index 6401d52899e..7b160a0efb5 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -2125,20 +2125,11 @@ when: never - if: '$VERTEX_AI_CREDENTIALS == null' when: never - -.rails:rules:ee-gitlab-duo-chat-optional: - rules: - - !reference [".rails:rules:ee-gitlab-duo-chat-base", rules] - <<: *if-merge-request + changes: *ai-patterns when: manual allow_failure: true -.rails:rules:ee-gitlab-duo-chat-fast: - rules: - - !reference [".rails:rules:ee-gitlab-duo-chat-base", rules] - - <<: *if-merge-request - changes: *ai-patterns - .rails:rules:as-if-foss-migration: rules: - !reference [".strict-ee-only-rules", rules] diff --git a/.gitlab/issue_templates/Security developer workflow.md b/.gitlab/issue_templates/Security developer workflow.md index d7ed4bf30e4..22b87786fb3 100644 --- a/.gitlab/issue_templates/Security developer workflow.md +++ b/.gitlab/issue_templates/Security developer workflow.md @@ -28,19 +28,19 @@ After your merge request has been approved according to our [approval guidelines ## Backports -- [ ] Once the MR is ready to be merged, create MRs targeting the latest 3 stable branches - * The 3 stable branches correspond to the versions in the title of the Security Release Tracking Issue. +- [ ] Once the MR is ready to be merged, create MRs targeting the latest 3 stable branches. + * The 3 stable branches correspond to the versions in the title of the [Security Release Tracking Issue]. * At this point, it might be easy to squash the commits from the MR into one * You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [secpick documentation] - [ ] Create each MR targeting the stable branch `X-Y-stable`, using the [Security Release merge request template]. * Every merge request will have its own set of to-dos, so make sure to complete those. - [ ] On the "Related merge requests" section, ensure that `4` merge requests are associated: The one targeting `master` and the `3` backports. -- [ ] If this issue requires less than `4` merge requests, post a message on the Security Release Tracking Issue and ping the Release Managers. +- [ ] If this issue requires less than `4` merge requests, add the ~"reduced backports" label. ## Assigning to a release -- [ ] **IMPORTANT**: When this issue is ready for release (Default branch MR and backports are approved and ready to be merged), apply the ~"security-target" label. - * The `gitlab-release-tools-bot` evaluates and links issues with the label to the next planned security release tracking issue. If the bot finds the issue is not ready to be included in the security release, it will leave a comment on the issue explaining what needs to be done. +- [ ] **IMPORTANT**: When this issue is ready for release (Default branch MR and backports are approved and ready to be merged), apply the ~"security-target" label. + * The `gitlab-release-tools-bot` evaluates and links issues with the label to the next planned security release tracking issue. If the bot finds the issue is not ready to be included in the security release, it will leave a comment on the issue explaining what needs to be done. * This issue will only be included in a security release if it is successfully linked to the security release tracking issue. ## Documentation and final details @@ -82,5 +82,6 @@ After your merge request has been approved according to our [approval guidelines [issue as linked]: https://docs.gitlab.com/ee/user/project/issues/related_issues.html#add-a-linked-issue [issue really needs to follow the security release workflow]: https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/developer.md#making-sure-the-issue-needs-to-follow-the-security-release-workflow [breaking changes workflow]: https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/far_reaching_impact_fixes_or_breaking_change_fixes.md +[Security Release Tracking Issue]: https://gitlab.com/gitlab-org/gitlab/-/issues/?label_name%5B%5D=upcoming%20security%20release /label ~security ~"security-notifications" diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml index 4bb700df401..a3b6d17e24e 100644 --- a/.rubocop_todo/layout/line_length.yml +++ b/.rubocop_todo/layout/line_length.yml @@ -1237,7 +1237,6 @@ Layout/LineLength: - 'ee/lib/gitlab/geo/git_ssh_proxy.rb' - 'ee/lib/gitlab/geo/health_check.rb' - 'ee/lib/gitlab/geo/jwt_request_decoder.rb' - - 'ee/lib/gitlab/geo/log_cursor/events/repository_created_event.rb' - 'ee/lib/gitlab/geo/registry_batcher.rb' - 'ee/lib/gitlab/geo/replication/blob_downloader.rb' - 'ee/lib/gitlab/geo/replicator.rb' diff --git a/.rubocop_todo/style/if_unless_modifier.yml b/.rubocop_todo/style/if_unless_modifier.yml index cd1c26b2330..70727e74805 100644 --- a/.rubocop_todo/style/if_unless_modifier.yml +++ b/.rubocop_todo/style/if_unless_modifier.yml @@ -596,7 +596,6 @@ Style/IfUnlessModifier: - 'ee/lib/gitlab/geo/git_ssh_proxy.rb' - 'ee/lib/gitlab/geo/health_check.rb' - 'ee/lib/gitlab/geo/log_cursor/daemon.rb' - - 'ee/lib/gitlab/geo/log_cursor/events/repository_deleted_event.rb' - 'ee/lib/gitlab/geo/oauth/logout_token.rb' - 'ee/lib/gitlab/geo/replication/blob_downloader.rb' - 'ee/lib/gitlab/geo/replicator.rb' @@ -546,7 +546,7 @@ gem 'kas-grpc', '~> 0.3.0', feature_category: :deployment_management gem 'grpc', '~> 1.58.0' # rubocop:todo Gemfile/MissingFeatureCategory -gem 'google-protobuf', '~> 3.25' # rubocop:todo Gemfile/MissingFeatureCategory +gem 'google-protobuf', '~> 3.25', '>= 3.25.1' # rubocop:todo Gemfile/MissingFeatureCategory gem 'toml-rb', '~> 2.2.0' # rubocop:todo Gemfile/MissingFeatureCategory diff --git a/Gemfile.checksum b/Gemfile.checksum index 750b2c40e5b..c04ec4641c3 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -244,16 +244,16 @@ {"name":"google-cloud-errors","version":"1.3.0","platform":"ruby","checksum":"450b681e24c089a20721a01acc4408bb4a7b0df28c175aaab488da917480d64b"}, {"name":"google-cloud-profiler-v2","version":"0.4.0","platform":"ruby","checksum":"53fc2ab175d08f54233c644310d47798feac996220916815c4fb44c937b5d3e3"}, {"name":"google-cloud-storage","version":"1.44.0","platform":"ruby","checksum":"299a1e055c9277c8120f7c10d21d37e4d8c17c7b963350c0e0bff7e9d9a570ea"}, -{"name":"google-protobuf","version":"3.25.0","platform":"aarch64-linux","checksum":"4455602758a60bd698a57c7210efc440523523fbe0c0c712624e57bb02c6c9d4"}, -{"name":"google-protobuf","version":"3.25.0","platform":"arm64-darwin","checksum":"c1ba0bb5504155f5bd0d11d649316ff52cef5b2a1e7ce876497815f98be3c5a6"}, -{"name":"google-protobuf","version":"3.25.0","platform":"java","checksum":"7006d8485d6c729c081a7eb8592d8c494fd8716863a7fb7ad7c76188eafc41a5"}, -{"name":"google-protobuf","version":"3.25.0","platform":"ruby","checksum":"b51632d900b633fbd6164784351bee93001dfd3f32bd18f6505fc97d64e1a1a1"}, -{"name":"google-protobuf","version":"3.25.0","platform":"x64-mingw-ucrt","checksum":"e4935e41e0f3c32fe96e496803de61d36273474ebb72ac7ee9db3a4ecb4b5cd6"}, -{"name":"google-protobuf","version":"3.25.0","platform":"x64-mingw32","checksum":"42b13346a1be8346e4d62a41ac7150f374ca5d254b3bb4bf3bc817de522ce969"}, -{"name":"google-protobuf","version":"3.25.0","platform":"x86-linux","checksum":"7f391788f013778ffae197a184481ff24265a977d1cb2270b13a5af1ba2f53d5"}, -{"name":"google-protobuf","version":"3.25.0","platform":"x86-mingw32","checksum":"2f42a5738af0a874b35b228a2df8de21a58fa265627cfd0fa57edaea160c1087"}, -{"name":"google-protobuf","version":"3.25.0","platform":"x86_64-darwin","checksum":"c3d4a144d8f4d61193ab1a4c5d52e2d40562ba13e07eeca1fca34bc59212c352"}, -{"name":"google-protobuf","version":"3.25.0","platform":"x86_64-linux","checksum":"c6a76175c921b300ee62b21d36e8a9c07f0a4967a17be0671a83c57d7bf9bd0f"}, +{"name":"google-protobuf","version":"3.25.1","platform":"aarch64-linux","checksum":"ac359f7dff48444fee35b1720d5fe4c3a15e1ce1d1cf2b01720e78e0c3c60e59"}, +{"name":"google-protobuf","version":"3.25.1","platform":"arm64-darwin","checksum":"9db6f8a7185d0109934db2f68defff7cba36b0e5816eb3b7aff8c35c61ac4cb5"}, +{"name":"google-protobuf","version":"3.25.1","platform":"java","checksum":"e02d624fafa42ddd27770ab3824d90fd5833dfc22e5778f4b72f5e33823795cf"}, +{"name":"google-protobuf","version":"3.25.1","platform":"ruby","checksum":"e740e099193f8dc4db638326e23868d6c799dbd5ae2fd7565e78d1530cc6d1a3"}, +{"name":"google-protobuf","version":"3.25.1","platform":"x64-mingw-ucrt","checksum":"33f9ef7fb931d4f9226bf7c5e6dc7965d71be65202ddab5f918e11d2b094c247"}, +{"name":"google-protobuf","version":"3.25.1","platform":"x64-mingw32","checksum":"61aad72c3db95719d39d371127124667f2bf136f09050fe74ca9c5e7b84b70de"}, +{"name":"google-protobuf","version":"3.25.1","platform":"x86-linux","checksum":"621ea865943efb085810dd76f35913aa9a8aff24ea358fd96b58291d9067f2a1"}, +{"name":"google-protobuf","version":"3.25.1","platform":"x86-mingw32","checksum":"94974547d65cf72fa5474dc43e18148d6478f3271fa81531c8333940b07779fd"}, +{"name":"google-protobuf","version":"3.25.1","platform":"x86_64-darwin","checksum":"48324e6f17f4a6b478d9f6c844e333ef4d88d82558c44ef87c588adba3a5ff40"}, +{"name":"google-protobuf","version":"3.25.1","platform":"x86_64-linux","checksum":"956d89256ed61cd0407a4e635a2286b8d478ca98075f4f398c30f91b765e9c54"}, {"name":"googleapis-common-protos","version":"1.4.0","platform":"ruby","checksum":"da2380fb5ab1563580816c74e8d684ac17512c3654c829a3ee84f6d6139de382"}, {"name":"googleapis-common-protos-types","version":"1.5.0","platform":"ruby","checksum":"5769cf7376abc86ef7f5897a4aaca1d5c5a3c49ddabeddd2c251fcf8155f858b"}, {"name":"googleauth","version":"1.3.0","platform":"ruby","checksum":"51dd7362353cf1e90a2d01e1fb94321ae3926c776d4dc4a79db65230217ffcc2"}, diff --git a/Gemfile.lock b/Gemfile.lock index c083cca8d25..1b9ebfe61b9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -787,7 +787,7 @@ GEM google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - google-protobuf (3.25.0) + google-protobuf (3.25.1) googleapis-common-protos (1.4.0) google-protobuf (~> 3.14) googleapis-common-protos-types (~> 1.2) @@ -1899,7 +1899,7 @@ DEPENDENCIES google-apis-serviceusage_v1 (~> 0.28.0) google-apis-sqladmin_v1beta4 (~> 0.41.0) google-cloud-storage (~> 1.44.0) - google-protobuf (~> 3.25) + google-protobuf (~> 3.25, >= 3.25.1) gpgme (~> 2.0.23) grape (~> 1.7.1) grape-entity (~> 0.10.0) @@ -2098,4 +2098,4 @@ DEPENDENCIES yajl-ruby (~> 1.4.3) BUNDLED WITH - 2.4.21 + 2.4.22 diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/rebase.stories.js b/app/assets/javascripts/vue_merge_request_widget/components/checks/rebase.stories.js index c0ac1818ffa..a4594409977 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/rebase.stories.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/rebase.stories.js @@ -63,7 +63,7 @@ const Template = ({ apolloProvider, check: { identifier: 'need_rebase', - status: failed ? 'failed' : 'passed', + status: failed ? 'FAILED' : 'SUCCESS', }, mr: { onlyAllowMergeIfPipelineSucceeds }, canCreatePipelineInTargetProject, diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/rebase.vue b/app/assets/javascripts/vue_merge_request_widget/components/checks/rebase.vue index 72140c22a89..63fa90fcc7a 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/rebase.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/rebase.vue @@ -65,8 +65,9 @@ export default { }, showRebaseWithoutPipeline() { return ( - !this.mr.onlyAllowMergeIfPipelineSucceeds || - (this.mr.onlyAllowMergeIfPipelineSucceeds && this.mr.allowMergeOnSkippedPipeline) + this.state.userPermissions.pushToSourceBranch && + (!this.mr.onlyAllowMergeIfPipelineSucceeds || + (this.mr.onlyAllowMergeIfPipelineSucceeds && this.mr.allowMergeOnSkippedPipeline)) ); }, isForkMergeRequest() { @@ -85,10 +86,8 @@ export default { ); }, tertiaryActionsButtons() { - if (this.check.result === 'success') return []; - return [ - { + this.state.userPermissions.pushToSourceBranch && { text: s__('mrWidget|Rebase'), loading: this.isMakingRequest || this.rebaseInProgress, testId: 'standard-rebase-button', diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue index 3c2d8efaffc..6de041d8f0d 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue @@ -59,6 +59,7 @@ export default { apollo: { state: { query: readyToMergeQuery, + fetchPolicy: fetchPolicies.NO_CACHE, variables() { return this.mergeRequestQueryVariables; }, @@ -349,12 +350,6 @@ export default { eventHub.$on('ApprovalUpdated', this.updateGraphqlState); eventHub.$on('MRWidgetUpdateRequested', this.updateGraphqlState); eventHub.$on('mr.discussion.updated', this.updateGraphqlState); - - if (this.glFeatures.widgetPipelinePassSubscriptionUpdate) { - this.$apollo.queries.state.setOptions({ - fetchPolicy: fetchPolicies.NO_CACHE, - }); - } }, beforeDestroy() { eventHub.$off('ApprovalUpdated', this.updateGraphqlState); diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 08bee6cbcf8..ce0c8291eda 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -45,7 +45,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo push_frontend_feature_flag(:ci_job_failures_in_mr, project) push_frontend_feature_flag(:mr_pipelines_graphql, project) push_frontend_feature_flag(:notifications_todos_buttons, current_user) - push_frontend_feature_flag(:widget_pipeline_pass_subscription_update, project) push_frontend_feature_flag(:mr_request_changes, current_user) end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 284495a1d97..4b548405bb9 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -705,13 +705,21 @@ module Ci end def artifacts_public? - return true unless Feature.enabled?(:non_public_artifacts, type: :development) + return true if Feature.disabled?(:non_public_artifacts, type: :development) + + return true if job_artifacts_archive.nil? # To backward compatibility return true if no artifacts found + + job_artifacts_archive.public_access? + end + + def artifact_is_public_in_config? + return true if Feature.disabled?(:non_public_artifacts, type: :development) artifacts_public = options.dig(:artifacts, :public) return true if artifacts_public.nil? # Default artifacts:public to true - options.dig(:artifacts, :public) + artifacts_public end def artifacts_metadata_entry(path, **options) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index faa79f8f49c..7ee96d6796e 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -415,7 +415,6 @@ module Ci pipeline.run_after_commit do next if pipeline.child? - next unless Feature.enabled?(:widget_pipeline_pass_subscription_update, project) || project.only_allow_merge_if_pipeline_succeeds?(inherit_group_setting: true) pipeline.all_merge_requests.opened.each do |merge_request| GraphqlTriggers.merge_request_merge_status_updated(merge_request) diff --git a/app/services/ci/job_artifacts/create_service.rb b/app/services/ci/job_artifacts/create_service.rb index c09b0cf81f1..b04e73c69ee 100644 --- a/app/services/ci/job_artifacts/create_service.rb +++ b/app/services/ci/job_artifacts/create_service.rb @@ -132,7 +132,7 @@ module Ci return accessibility if accessibility.present? - job.artifacts_public? ? :public : :private + job.artifact_is_public_in_config? ? :public : :private end def parse_artifact(artifact) diff --git a/config/feature_flags/development/widget_pipeline_pass_subscription_update.yml b/config/feature_flags/development/widget_pipeline_pass_subscription_update.yml deleted file mode 100644 index 764b0a59291..00000000000 --- a/config/feature_flags/development/widget_pipeline_pass_subscription_update.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: widget_pipeline_pass_subscription_update -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132353 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/428633 -milestone: '16.6' -type: development -group: group::code review -default_enabled: false diff --git a/doc/architecture/blueprints/new_diffs.md b/doc/architecture/blueprints/new_diffs.md index 57e84b722e2..91c568517da 100644 --- a/doc/architecture/blueprints/new_diffs.md +++ b/doc/architecture/blueprints/new_diffs.md @@ -118,6 +118,108 @@ To measure our success, we need to set meaningful metrics. These metrics should --- <sup>1</sup>: [The Performance Inequality Gap, 2023](https://infrequently.org/2022/12/performance-baseline-2023/) +### Front end + +Ideally, we would meet our definition of done and our accountability metrics on our first try. +We also need to continue to stay within those boundaries as we move forward. To ensure this, +we need to design an application architecture that: + +1. Is: + 1. Scalable. + 1. Malleable. + 1. Flexible. +1. Considers itself a mission-critical part of the overall GitLab product. +1. Treats itself as a complex, unique application with concerns that cannot be addressed + as side effects of other parts of the product. +1. Can handle data access/format changes without making UI changes. +1. Can handle UI changes without making data access/format changes. +1. Provides a hookable, inspectable API and avoids code coupling. +1. Separates: + - State and application data. + - Application behavior and UI. + - Data access and network access. + +#### High-level implementation + +(See [New Diffs: Technical Architecture Design](https://gitlab.com/gitlab-org/gitlab/-/issues/431276) for nicer visuals of this chart) + +```mermaid +flowchart TB + classDef sticky fill:#d0cabf, color:black + stickyMetricsA>"Metrics 3, 4, & 5 apply to<br>the entire front end application"] + + stickyMetricsA -.- fe + fe + + Socket((WebSocket)) + + be + +subgraph fe [Front End] + stickyMetricsB>"Metrics 1 & 2 apply<br>to all UI elements"] + stickyInbound>"All data is formatted precisely<br>how the UI needs to interact with it"] + stickyOutbound>"All data is formatted precisely<br>how the back end expects it"] + stickyIdb>"Long-term. + + e.g. diffs, MRs, emoji, notes, drafts, user-only data<br>like file reviews, collapse states, etc."] + stickySession>"Session-term. + + e.g. selected tab, scroll position,<br>temporary changes to user settings, etc."] + + Events([Event Hub]) + UI[UI] + uiState((Local State)) + Logic[Application Logic] + Normalizer[Data Normalizer] + Inbound{{Inbound Contract}} + Outbound{{Outbound Contract}} + Data[Data Access] + idb((indexedDB)) + session((sessionStorage)) + Network[Network Access] +end + +subgraph be [Back End] + stickyApi>"A large list of defined actions a<br>Diffs/Merge Request UI could perform. + + e.g.: <code>mergeRequest:notes:saveDraft</code> or<br><code>mergeRequest:changeStatus</code> (with <br><code>status: 'draft'</code> or <code>status: 'ready'</code>, etc.). + + Must not expose any implementation detail,<br>like models, storage structure, etc."] + API[Activities API] + unk[\"?"/] + + API -.- stickyApi +end + + %% Make stickies look like paper sort of? + class stickyMetricsA,stickyMetricsB,stickyInbound,stickyOutbound,stickyIdb,stickySession,stickyApi sticky + + UI <--> uiState + stickyMetricsB -.- UI + Network ~~~ stickyMetricsB + + Logic <--> Normalizer + + Normalizer --> Outbound + Outbound --> Data + Inbound --> Normalizer + Data --> Inbound + + Inbound -.- stickyInbound + Outbound -.- stickyOutbound + + Data <--> idb + Data <--> session + idb -.- stickyIdb + session -.- stickySession + + Events <--> UI + Events <--> Logic + Events <--> Data + Events <--> Network + + Network --> Socket --> API --> unk +``` <!-- This section should contain enough information that the specifics of your change are understandable. This may include API specs (though not always diff --git a/doc/development/ai_features/duo_chat.md b/doc/development/ai_features/duo_chat.md index 2fde672aa7e..dfaad73220f 100644 --- a/doc/development/ai_features/duo_chat.md +++ b/doc/development/ai_features/duo_chat.md @@ -109,28 +109,17 @@ make sure a new fixture is generated and committed together with the change. ## Running the rspecs tagged with `real_ai_request` -The following CI jobs for GitLab project run the rspecs tagged with `real_ai_request`: - -- `rspec-ee unit gitlab-duo-chat-zeroshot`: - the job runs `ee/spec/lib/gitlab/llm/chain/agents/zero_shot/executor_real_requests_spec.rb`. - The job is optionally triggered and allowed to fail. - -- `rspec-ee unit gitlab-duo-chat-qa`: - The job runs the QA evaluation tests in - `ee/spec/lib/gitlab/llm/chain/agents/zero_shot/qa_evaluation_spec.rb`. - The job is optionally triggered and allowed to fail. - -- `rspec-ee unit gitlab-duo-chat-qa-fast`: - The job runs a single QA evaluation test from `ee/spec/lib/gitlab/llm/chain/agents/zero_shot/qa_evaluation_spec.rb`. - The job is always run and not allowed to fail. Although there's a chance that the QA test still might fail, - it is cheap and fast to run and intended to prevent a regression in the QA test helpers. +The rspecs tagged with the metadata `real_ai_request` can be run in GitLab project's CI by triggering +`rspec-ee unit gitlab-duo-chat`. +The former runs with Vertex APIs enabled. The CI jobs are optional and allowed to fail to account for +the non-deterministic nature of LLM responses. ### Management of credentials and API keys for CI jobs All API keys required to run the rspecs should be [masked](../../ci/variables/index.md#mask-a-cicd-variable) The exception is GCP credentials as they contain characters that prevent them from being masked. -Because the CI jobs need to run on MR branches, GCP credentials cannot be added as a protected variable +Because `rspec-ee unit gitlab-duo-chat` needs to run on MR branches, GCP credentials cannot be added as a protected variable and must be added as a regular CI variable. For security, the GCP credentials and the associated project added to GitLab project's CI must not be able to access any production infrastructure and sandboxed. diff --git a/doc/editor_extensions/visual_studio_code/index.md b/doc/editor_extensions/visual_studio_code/index.md index 70d0c79cfbf..ed56bed0be9 100644 --- a/doc/editor_extensions/visual_studio_code/index.md +++ b/doc/editor_extensions/visual_studio_code/index.md @@ -37,6 +37,7 @@ you can [configure](https://marketplace.visualstudio.com/items?itemName=GitLab.g - [Features to display or hide](https://gitlab.com/gitlab-org/gitlab-vscode-extension#extension-settings). - [Self-signed certificate](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#self-signed-certificates) information. - [Code Suggestions](../../user/project/repository/code_suggestions/index.md). +- [GitLab Duo Chat](../../user/gitlab_duo_chat.md#gitlab-workflow-extension-for-vs-code). ## Report issues with the extension diff --git a/doc/user/gitlab_duo_chat.md b/doc/user/gitlab_duo_chat.md index b763cd2bd27..92d46aae550 100644 --- a/doc/user/gitlab_duo_chat.md +++ b/doc/user/gitlab_duo_chat.md @@ -58,6 +58,30 @@ To use this feature, at least one group you're a member of must: NOTE: Only the last 50 messages are retained in the chat history. The chat history expires 3 days after last use. +## Use GitLab Duo Chat in the Web IDE and VSCode **(ULTIMATE SAAS EXPERIMENT)** + +> Introduced in GitLab 16.6 as an [EXPERIMENT](../policy/experiment-beta-support.md#experiment). + +### Web IDE + +To use GitLab Duo Chat in the Web IDE: + +1. On the left sidebar, select **Search or go to** and find your project. +1. Select a file. Then in the upper right, select **Edit > Open in Web IDE**. +1. On the left sidebar, select **GitLab Duo Chat**. A drawer opens. +1. In the text box, enter your question and press **Enter** or select **Send**. It may take a few seconds for the interactive AI chat to produce an answer. + +### GitLab Workflow extension for VS Code + +To disable GitLab Duo Chat in VS Code, go to the VS Code extension settings and clear the **Enable GitLab Duo Chat assistant** checkbox. + +To use GitLab Duo Chat in VS Code: + +1. Install the [GitLab Workflow extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow) in VS Code. +1. In VS Code, open your GitLab project. +1. On the left side of the toolbar, select **GitLab Duo Chat**. A drawer opens. +1. In the text box, enter your question and press **Enter** or select **Send**. It may take a few seconds for the interactive AI chat to produce an answer. + ## Give Feedback Your feedback is important to us as we continually enhance your GitLab Duo Chat experience: diff --git a/doc/user/group/saml_sso/group_sync.md b/doc/user/group/saml_sso/group_sync.md index 3ff0668f436..587da517be9 100644 --- a/doc/user/group/saml_sso/group_sync.md +++ b/doc/user/group/saml_sso/group_sync.md @@ -77,11 +77,19 @@ example configurations for [Azure AD](../../../user/group/saml_sso/example_saml_ ## Configure SAML Group Links -When SAML is enabled, users with the Maintainer or Owner role -see a new menu item in group **Settings > SAML Group Links**. You can configure one or more **SAML Group Links** to map -a SAML identity provider group name to a GitLab role. This can be done for a top-level group or any subgroup. - -SAML Group Sync only manages a group if that group has one or more SAML group links. If a SAML group link is created then removed, the user remains in the group until they are removed from the group in the identity provider. +When SAML is enabled, users with the Maintainer or Owner role see a new menu +item in group **Settings > SAML Group Links**. + +- You can configure one or more **SAML Group Links** to map a SAML identity +provider group name to a GitLab role. +- Members of the SAML identity provider group are added as members of the GitLab +group on their next SAML sign-in. +- Group membership is evaluated each time a user signs in using SAML. +- SAML Group Links can be configured for a top-level group or any subgroup. +- SAML Group Sync only manages a group if that group has one or more SAML group +links. + - If a SAML group link is created then removed, the user remains in the +group until they are removed from the group in the identity provider. Prerequisites: @@ -109,8 +117,6 @@ Users granted: - A lower or the same role with Group Sync are displayed as having [inherited membership](../../project/members/index.md#display-inherited-members) of the group. -SAML group membership is evaluated each time a user signs in. - ### Use the API > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/290367) in GitLab 15.3. diff --git a/doc/user/project/web_ide/index.md b/doc/user/project/web_ide/index.md index fb2bd707c56..f2548806137 100644 --- a/doc/user/project/web_ide/index.md +++ b/doc/user/project/web_ide/index.md @@ -244,3 +244,7 @@ When you type in the Web IDE, you might get a four-character offset. To resolve - Modify your `"editor.font"` setting. For more information, see [VS Code issue 80170](https://github.com/microsoft/vscode/issues/80170). + +## Related topics + +- [Use GitLab Duo Chat in the Web IDE](../../gitlab_duo_chat.md#web-ide). diff --git a/lefthook.yml b/lefthook.yml index 8ba1f335906..c5b9ccf3392 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -63,7 +63,7 @@ pre-push: tags: backend frontend view haml files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD | while read file;do git diff --unified=1 $(git merge-base origin/master HEAD)..HEAD $file | grep -Fqe '_(' && echo $file;done; true glob: '*.{haml,rb,js,vue}' - run: tooling/bin/gettext_extractor /dev/stdout --silent | diff - locale/gitlab.pot + run: tooling/bin/gettext_extractor /dev/stdout --silent | diff - locale/gitlab.pot || ( echo "\nPO files need to be updated. Try running bin/rake gettext:regenerate" && exit 1 ) docs-metadata: # See https://docs.gitlab.com/ee/development/documentation/#metadata tags: documentation style files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD diff --git a/scripts/duo_chat/reporter.rb b/scripts/duo_chat/reporter.rb index e72a393694f..686a49164a7 100755 --- a/scripts/duo_chat/reporter.rb +++ b/scripts/duo_chat/reporter.rb @@ -5,7 +5,7 @@ require 'gitlab' require 'json' class Reporter - IDENTIFIABLE_NOTE_TAG = 'gitlab-org/ai-powered/ai-framework:duo-chat-qa-evaluation' + IDENTIFIABLE_NOTE_TAG = 'gitlab-org/ai-powered/ai-framework:duo-chat-qa-evaluation-' GRADE_TO_EMOJI_MAPPING = { correct: ":white_check_mark:", @@ -25,7 +25,7 @@ class Reporter .merge_request_notes(ci_project_id, merge_request_iid) .auto_paginate .select do |note| - note.body.include? IDENTIFIABLE_NOTE_TAG + note.body.include? note_identifier_tag end note = report_notes.max_by { |note| Time.parse(note.created_at) } @@ -47,13 +47,17 @@ class Reporter private def report_filename - ENV['QA_EVAL_REPORT_FILENAME'] + "#{ENV['DUO_RSPEC']}.md" end def artifact_path File.join(ENV['CI_PROJECT_DIR'], report_filename) end + def note_identifier_tag + "#{IDENTIFIABLE_NOTE_TAG}#{ENV['DUO_RSPEC']}" + end + def com_gitlab_client @com_gitlab_client ||= Gitlab.client( endpoint: "https://gitlab.com/api/v4", @@ -63,7 +67,7 @@ class Reporter def report_note report = <<~MARKDOWN - <!-- #{IDENTIFIABLE_NOTE_TAG} --> + <!-- #{note_identifier_tag} --> ## GitLab Duo Chat QA evaluation @@ -101,7 +105,7 @@ class Reporter if report.length > 1000000 return <<~MARKDOWN - <!-- #{IDENTIFIABLE_NOTE_TAG} --> + <!-- #{note_identifier_tag} --> ## GitLab Duo Chat QA evaluation @@ -121,7 +125,7 @@ class Reporter def report_data @report_data ||= Dir[File.join(ENV['CI_PROJECT_DIR'], "tmp/duo_chat/qa*.json")] - .flat_map { |file| JSON.parse(File.read(file)) } + .map { |file| JSON.parse(File.read(file)) } end def eval_content diff --git a/spec/frontend/vue_merge_request_widget/components/checks/rebase_spec.js b/spec/frontend/vue_merge_request_widget/components/checks/rebase_spec.js index d6c01aee3b1..d621999337d 100644 --- a/spec/frontend/vue_merge_request_widget/components/checks/rebase_spec.js +++ b/spec/frontend/vue_merge_request_widget/components/checks/rebase_spec.js @@ -28,7 +28,7 @@ const mockPipelineNodes = [ const mockQueryHandler = ({ rebaseInProgress = false, targetBranch = '', - pushToSourceBranch = false, + pushToSourceBranch = true, nodes = mockPipelineNodes, } = {}) => jest.fn().mockResolvedValue({ @@ -279,7 +279,7 @@ describe('Merge request merge checks rebase component', () => { await waitForPromises(); - expect(findRebaseWithoutCiButton().exists()).toBe(true); + expect(findRebaseWithoutCiButton().exists()).toBe(false); }); }); diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 2e552c8d524..07052113d5d 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -987,6 +987,70 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def describe '#artifacts_public?' do subject { build.artifacts_public? } + context 'when non_public_artifacts flag is disabled' do + before do + stub_feature_flags(non_public_artifacts: false) + end + + context 'artifacts with defaults - public' do + let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) } + + it { is_expected.to be_truthy } + end + + context 'non public artifacts' do + let(:build) { create(:ci_build, :private_artifacts, pipeline: pipeline) } + + it { is_expected.to be_truthy } + end + end + + context 'artifacts with defaults - public' do + let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) } + + it { is_expected.to be_truthy } + end + + context 'non public artifacts' do + let(:build) { create(:ci_build, :private_artifacts, pipeline: pipeline) } + + it { is_expected.to be_falsey } + end + + context 'no artifacts' do + let(:build) { create(:ci_build, pipeline: pipeline) } + + it { is_expected.to be_truthy } + end + end + + describe '#artifact_is_public_in_config?' do + subject { build.artifact_is_public_in_config? } + + context 'when non_public_artifacts flag is disabled' do + before do + stub_feature_flags(non_public_artifacts: false) + end + + context 'artifacts with defaults' do + let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) } + + it { is_expected.to be_truthy } + end + + context 'non public artifacts' do + let(:build) { create(:ci_build, :with_private_artifacts_config, pipeline: pipeline) } + + it { is_expected.to be_truthy } + end + + context 'public artifacts' do + let(:build) { create(:ci_build, :with_public_artifacts_config, pipeline: pipeline) } + + it { is_expected.to be_truthy } + end + end + context 'artifacts with defaults' do let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) } @@ -994,10 +1058,22 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def end context 'non public artifacts' do - let(:build) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline) } + let(:build) { create(:ci_build, :with_private_artifacts_config, pipeline: pipeline) } it { is_expected.to be_falsey } end + + context 'public artifacts' do + let(:build) { create(:ci_build, :with_public_artifacts_config, pipeline: pipeline) } + + it { is_expected.to be_truthy } + end + + context 'no artifacts' do + let(:build) { create(:ci_build, pipeline: pipeline) } + + it { is_expected.to be_truthy } + end end describe '#artifacts_expired?' do diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 9696ba7b3ee..61522c1e4dd 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -2028,17 +2028,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep, feature_category: end end - context 'when only_allow_merge_if_pipeline_succeeds? returns false and widget_pipeline_pass_subscription_update disabled' do - let(:only_allow_merge_if_pipeline_succeeds?) { false } - - before do - stub_feature_flags(widget_pipeline_pass_subscription_update: false) - end - - it_behaves_like 'state transition not triggering GraphQL subscription mergeRequestMergeStatusUpdated' - end - - context 'when only_allow_merge_if_pipeline_succeeds? returns false and widget_pipeline_pass_subscription_update enabled' do + context 'when only_allow_merge_if_pipeline_succeeds? returns false' do let(:only_allow_merge_if_pipeline_succeeds?) { false } it_behaves_like 'triggers GraphQL subscription mergeRequestMergeStatusUpdated' do diff --git a/spec/requests/api/ci/job_artifacts_spec.rb b/spec/requests/api/ci/job_artifacts_spec.rb index b96ba356855..9fb3f7e85ba 100644 --- a/spec/requests/api/ci/job_artifacts_spec.rb +++ b/spec/requests/api/ci/job_artifacts_spec.rb @@ -187,7 +187,7 @@ RSpec.describe API::Ci::JobArtifacts, feature_category: :build_artifacts do end context 'when project is public with artifacts that are non public' do - let(:job) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline) } + let(:job) { create(:ci_build, :private_artifacts, :with_private_artifacts_config, pipeline: pipeline) } it 'rejects access to artifacts' do project.update_column(:visibility_level, Gitlab::VisibilityLevel::PUBLIC) @@ -433,7 +433,7 @@ RSpec.describe API::Ci::JobArtifacts, feature_category: :build_artifacts do context 'when public project guest and artifacts are non public' do let(:api_user) { guest } - let(:job) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline) } + let(:job) { create(:ci_build, :private_artifacts, :with_private_artifacts_config, pipeline: pipeline) } before do project.update_column(:visibility_level, @@ -639,7 +639,7 @@ RSpec.describe API::Ci::JobArtifacts, feature_category: :build_artifacts do end context 'when project is public with non public artifacts' do - let(:job) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline, user: api_user) } + let(:job) { create(:ci_build, :private_artifacts, :with_private_artifacts_config, pipeline: pipeline, user: api_user) } let(:visibility_level) { Gitlab::VisibilityLevel::PUBLIC } let(:public_builds) { true } diff --git a/spec/serializers/build_details_entity_spec.rb b/spec/serializers/build_details_entity_spec.rb index 874bcbfceaf..9ef1e91ebcd 100644 --- a/spec/serializers/build_details_entity_spec.rb +++ b/spec/serializers/build_details_entity_spec.rb @@ -281,7 +281,7 @@ RSpec.describe BuildDetailsEntity do end context 'when the build has non public archive type artifacts' do - let(:build) { create(:ci_build, :artifacts, :with_private_artifacts_config, pipeline: pipeline) } + let(:build) { create(:ci_build, :private_artifacts, :with_private_artifacts_config, pipeline: pipeline) } it 'does not expose non public artifacts' do expect(subject.keys).not_to include(:artifact) diff --git a/spec/services/ci/job_artifacts/create_service_spec.rb b/spec/services/ci/job_artifacts/create_service_spec.rb index a23ba250daf..ffb6bd9d145 100644 --- a/spec/services/ci/job_artifacts/create_service_spec.rb +++ b/spec/services/ci/job_artifacts/create_service_spec.rb @@ -139,12 +139,18 @@ RSpec.describe Ci::JobArtifacts::CreateService, :clean_gitlab_redis_shared_state shared_examples_for 'handling accessibility' do shared_examples 'public accessibility' do it 'sets accessibility to public level' do + subject + + expect(job.job_artifacts).not_to be_empty expect(job.job_artifacts).to all be_public_accessibility end end shared_examples 'private accessibility' do it 'sets accessibility to private level' do + subject + + expect(job.job_artifacts).not_to be_empty expect(job.job_artifacts).to all be_private_accessibility end end |