diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-20 21:08:32 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-20 21:08:32 +0300 |
commit | 995bcca3fc5544e5d2d8ee274dc9275d5b4ce375 (patch) | |
tree | 370881ef6e9de8f93ce5546b725b2f91b4072a5f /doc | |
parent | a5d7e614fe1d038a7f9e2af76106773b98e2b5e8 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'doc')
-rw-r--r-- | doc/api/releases/index.md | 2 | ||||
-rw-r--r-- | doc/architecture/blueprints/gitlab_agent_deployments/index.md | 163 | ||||
-rw-r--r-- | doc/development/ai_features.md | 37 | ||||
-rw-r--r-- | doc/development/gems.md | 4 | ||||
-rw-r--r-- | doc/development/testing_guide/best_practices.md | 134 | ||||
-rw-r--r-- | doc/user/packages/composer_repository/index.md | 6 | ||||
-rw-r--r-- | doc/user/project/members/index.md | 2 | ||||
-rw-r--r-- | doc/user/public_access.md | 14 |
8 files changed, 192 insertions, 170 deletions
diff --git a/doc/api/releases/index.md b/doc/api/releases/index.md index 86c23283588..3ec4b77a646 100644 --- a/doc/api/releases/index.md +++ b/doc/api/releases/index.md @@ -435,7 +435,7 @@ GET /projects/:id/releases/:tag_name/downloads/:direct_asset_path Example request: ```shell -curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/24/releases/v0.1/downloads/bin/asset.exe" +curl --location --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/24/releases/v0.1/downloads/bin/asset.exe" ``` ### Get the latest release diff --git a/doc/architecture/blueprints/gitlab_agent_deployments/index.md b/doc/architecture/blueprints/gitlab_agent_deployments/index.md index d8d26389d7d..09c30da1077 100644 --- a/doc/architecture/blueprints/gitlab_agent_deployments/index.md +++ b/doc/architecture/blueprints/gitlab_agent_deployments/index.md @@ -1,11 +1,11 @@ --- -status: proposed +status: implemented creation-date: "2022-11-23" authors: [ "@shinya.maeda" ] coach: "@DylanGriffith" approvers: [ "@nagyv-gitlab", "@cbalane", "@hustewart", "@hfyngvason" ] -owning-stage: "~devops::release" -participating-stages: [Configure, Release] +owning-stage: "~devops::deploy" +participating-stages: [Environments] --- <!-- vale gitlab.FutureTense = NO --> @@ -29,8 +29,6 @@ This blueprint describes how the association is established and how these domain - The cluster resources and events can be visualized per [GitLab Environment](../../../ci/environments/index.md). An environment-specific view scoped to the resources managed either directly or indirectly by a deployment commit. - Support both [GitOps mode](../../../user/clusters/agent/gitops.md#gitops-configuration-reference) and [CI Access mode](../../../user/clusters/agent/ci_cd_workflow.md#authorize-the-agent). - - NOTE: At the moment, we focus on the solution for CI Access mode. GitOps mode will have significant architectural changes _outside of_ this blueprint, - such as [Flux switching](https://gitlab.com/gitlab-org/gitlab/-/issues/357947) and [Manifest projects outside of the Agent configuration project](https://gitlab.com/groups/gitlab-org/-/epics/7704). In order to derisk potential rework, we'll revisit the GitOps mode after these upstream changes have been settled. ### Non-Goals @@ -41,22 +39,22 @@ This blueprint describes how the association is established and how these domain ### Overview -- GitLab Environment and Agent-managed Resource Group have 1-to-1 relationship. -- Agent-managed Resource Group tracks all resources produced by the connected [agent](../../../user/clusters/agent/index.md). This includes not only resources written in manifest files but also subsequently generated resources (e.g. `Pod`s created by `Deployment` manifest file). -- Agent-managed Resource Group renders dependency graph, such as `Deployment` => `ReplicaSet` => `Pod`. This is for providing ArgoCD-style resource view. -- Agent-managed Resource Group has the Resource Health status that represents a summary of resource statuses, such as `Healthy`, `Progressing` or `Degraded`. +- GitLab Environment and GitLab Agent For Kubernetes have 1-to-1 relationship. +- GitLab Environment tracks all resources produced by the connected [agent](../../../user/clusters/agent/index.md). This includes not only resources written in manifest files but also subsequently generated resources (for example, `Pod`s created by `Deployment` manifest file). +- GitLab Environment renders dependency graph, such as `Deployment` => `ReplicaSet` => `Pod`. This is for providing ArgoCD-style resource view. +- GitLab Environment has the Resource Health status that represents a summary of resource statuses, such as `Healthy`, `Progressing` or `Degraded`. ```mermaid flowchart LR subgraph Kubernetes["Kubernetes"] - subgraph ResourceGroupProduction["ResourceGroup"] + subgraph ResourceGroupProduction["Production"] direction LR ResourceGroupProductionService(["Service"]) ResourceGroupProductionDeployment(["Deployment"]) ResourceGroupProductionPod1(["Pod1"]) ResourceGroupProductionPod2(["Pod2"]) end - subgraph ResourceGroupStaging["ResourceGroup"] + subgraph ResourceGroupStaging["Staging"] direction LR ResourceGroupStagingService(["Service"]) ResourceGroupStagingDeployment(["Deployment"]) @@ -90,26 +88,18 @@ flowchart LR - GitLab Project and Agent have 1-to-many _direct_ relationship. Only one project can own a specific agent. - [GitOps mode](../../../user/clusters/agent/gitops.md#gitops-configuration-reference) - GitLab Project and Agent do _NOT_ have many-to-many _indirect_ relationship yet. This will be supported in [Manifest projects outside of the Agent configuration project](https://gitlab.com/groups/gitlab-org/-/epics/7704). - - Agent and Agent-managed Resource Group have 1-to-1 relationship. Inventory IDs are used to group Kubernetes resources. This might be changed in [Flux switching](https://gitlab.com/gitlab-org/gitlab/-/issues/357947). - [CI Access mode](../../../user/clusters/agent/ci_cd_workflow.md#authorize-the-agent) - GitLab Project and Agent have many-to-many _indirect_ relationship. The project owning the agent can [share the access with the other proejcts](../../../user/clusters/agent/ci_cd_workflow.md#authorize-the-agent-to-access-projects-in-your-groups). (NOTE: Technically, only running jobs inside the project are allowed to access the cluster due to job-token authentication.) - - Agent and Agent-managed Resource Group do _NOT_ have relationships yet. ### Issues -- Agent-managed Resource Group should have environment ID as the foreign key, which must be unique across resource groups. -- Agent-managed Resource Group should have parameters how to group resources in the associated cluster, for example, `namespace`, `lable` and `inventory-id` (GitOps mode only) can passed as parameters. -- Agent-managed Resource Group should be able to fetch all relevant resources, including both default resource kinds and other [Custom Resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/). -- Agent-managed Resource Group should be aware of dependency graph. -- Agent-managed Resource Group should be able to compute Resource Health status from the associated resources. +- GitLab Environment should have ID of GitLab Agent For Kubernetes as the foreign key. +- GitLab Environment should have parameters how to group resources in the associated cluster, for example, `namespace`, `lable` and `inventory-id` (GitOps mode only) can passed as parameters. +- GitLab Environment should be able to fetch all relevant resources, including both default resource kinds and other [Custom Resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/). +- GitLab Environment should be aware of dependency graph. +- GitLab Environment should be able to compute Resource Health status from the associated resources. -### Example: Pull-based deployment (GitOps mode) - -NOTE: -At the moment, we focus on the solution for CI Access mode. GitOps mode will have significant architectural changes _outside of_ this blueprint, -such as [Flux switching](https://gitlab.com/gitlab-org/gitlab/-/issues/357947) and [Manifest projects outside of the Agent configuration project](https://gitlab.com/groups/gitlab-org/-/epics/7704). In order to derisk potential rework, we'll revisit the GitOps mode after these upstream changes have been settled. - -### Example: Push-based deployment (CI access mode) +### Example This is an example of how the architecture works in push-based deployment. The feature is documented [here](../../../user/clusters/agent/ci_cd_workflow.md) as CI access mode. @@ -117,21 +107,21 @@ The feature is documented [here](../../../user/clusters/agent/ci_cd_workflow.md) ```mermaid flowchart LR subgraph ProductionKubernetes["Production Kubernetes"] - subgraph ResourceGroupProductionFrontend["ResourceGroup"] + subgraph ResourceGroupProductionFrontend["Production"] direction LR ResourceGroupProductionFrontendService(["Service"]) ResourceGroupProductionFrontendDeployment(["Deployment"]) ResourceGroupProductionFrontendPod1(["Pod1"]) ResourceGroupProductionFrontendPod2(["Pod2"]) end - subgraph ResourceGroupProductionBackend["ResourceGroup"] + subgraph ResourceGroupProductionBackend["Staging"] direction LR ResourceGroupProductionBackendService(["Service"]) ResourceGroupProductionBackendDeployment(["Deployment"]) ResourceGroupProductionBackendPod1(["Pod1"]) ResourceGroupProductionBackendPod2(["Pod2"]) end - subgraph ResourceGroupProductionPrometheus["ResourceGroup"] + subgraph ResourceGroupProductionPrometheus["Monitoring"] direction LR ResourceGroupProductionPrometheusService(["Service"]) ResourceGroupProductionPrometheusDeployment(["Deployment"]) @@ -202,21 +192,21 @@ The microservice project setup can be improved by [Multi-Project Deployment Pipe ```mermaid flowchart LR subgraph ProductionKubernetes["Production Kubernetes"] - subgraph ResourceGroupProductionFrontend["ResourceGroup"] + subgraph ResourceGroupProductionFrontend["Frontend"] direction LR ResourceGroupProductionFrontendService(["Service"]) ResourceGroupProductionFrontendDeployment(["Deployment"]) ResourceGroupProductionFrontendPod1(["Pod1"]) ResourceGroupProductionFrontendPod2(["Pod2"]) end - subgraph ResourceGroupProductionBackend["ResourceGroup"] + subgraph ResourceGroupProductionBackend["Backend"] direction LR ResourceGroupProductionBackendService(["Service"]) ResourceGroupProductionBackendDeployment(["Deployment"]) ResourceGroupProductionBackendPod1(["Pod1"]) ResourceGroupProductionBackendPod2(["Pod2"]) end - subgraph ResourceGroupProductionPrometheus["ResourceGroup"] + subgraph ResourceGroupProductionPrometheus["Monitoring"] direction LR ResourceGroupProductionPrometheusService(["Service"]) ResourceGroupProductionPrometheusDeployment(["Deployment"]) @@ -266,104 +256,18 @@ flowchart LR DeploymentPipelines -- "Deploy" --> ResourceGroupProductionBackend ``` -#### View all Agent-managed Resource Groups on production environment - -At the group-level, we can accumulate all environments match a specific tier, for example, -listing all environments with `production` tier from subsequent projects. -This is useful to see the entire Agent-managed Resource Groups on production environment. -The following diagram examplifies the relationship between GitLab group and Kubernetes resources: - -```mermaid -flowchart LR - subgraph Kubernetes["Kubernetes"] - subgraph ResourceGroupProduction["ResourceGroup"] - direction LR - ResourceGroupProductionService(["Service"]) - ResourceGroupProductionDeployment(["Deployment"]) - ResourceGroupProductionPod1(["Pod1"]) - ResourceGroupProductionPod2(["Pod2"]) - end - subgraph ResourceGroupStaging["ResourceGroup"] - direction LR - ResourceGroupStagingService(["Service"]) - ResourceGroupStagingDeployment(["Deployment"]) - ResourceGroupStagingPod1(["Pod1"]) - ResourceGroupStagingPod2(["Pod2"]) - end - end - - subgraph GitLab - subgraph Organization - OrganizationProduction["All resources on production"] - subgraph Frontend project - FrontendEnvironmentProduction["production environment"] - end - subgraph Backend project - BackendEnvironmentProduction["production environment"] - end - end - end - - FrontendEnvironmentProduction --- ResourceGroupProduction - BackendEnvironmentProduction --- ResourceGroupStaging - ResourceGroupProductionService -.- ResourceGroupProductionDeployment - ResourceGroupProductionDeployment -.- ResourceGroupProductionPod1 - ResourceGroupProductionDeployment -.- ResourceGroupProductionPod2 - ResourceGroupStagingService -.- ResourceGroupStagingDeployment - ResourceGroupStagingDeployment -.- ResourceGroupStagingPod1 - ResourceGroupStagingDeployment -.- ResourceGroupStagingPod2 - OrganizationProduction --- FrontendEnvironmentProduction - OrganizationProduction --- BackendEnvironmentProduction -``` - -A few notes: - -- In the future, we'd have more granular filters for resource search. - For example, there are two environments `production/us-region` and `production/eu-region` in each project - and show only resources in US region at the group-level. - This could be achivable by query filtering in PostgreSQL or label/namespace filtering in Kubernetes. -- Please see [Add dynamically populated organization-level environments page](https://gitlab.com/gitlab-org/gitlab/-/issues/241506) for more information. - ## Design and implementation details -NOTE: -The following solution might be only applicable for CI Access mode. GitOps mode will have significant architectural changes _outside of_ this blueprint, -such as [Flux switching](https://gitlab.com/gitlab-org/gitlab/-/issues/357947) and [Manifest projects outside of the Agent configuration project](https://gitlab.com/groups/gitlab-org/-/epics/7704). In order to derisk potential rework, we'll revisit the GitOps mode after these upstream changes have been settled. - ### Associate Environment with Agent -As a preliminary step, we allow users to explicitly define "which deployment job" uses "which agent" and deploy to "which namespace". The following keywords are supported in `.gitlab-ci.yml`. - -- `environment:kubernetes:agent` ... Define which agent the deployment job uses. It can select the appropriate context from the `KUBE_CONFIG`. -- `environment:kubernetes:namespace` ... Define which namespace the deployment job deploys to. It injects `KUBE_NAMESPACE` predefined variable into the job. This keyword already [exists](../../../ci/yaml/index.md#environmentkubernetes). - -Here is an example of `.gitlab-ci.yml`. - -```yaml -deploy-production: - environment: - name: production - kubernetes: - agent: path/to/agent/repository:agent-name - namespace: default - script: - - helm --context="$KUBE_CONTEXT" --namespace="$KUBE_NAMESPACE" upgrade --install -``` - -When a deployment job is created, GitLab persists the relationship of specified agent, namespace and deployment job. If the CI job is NOT authorized to access the agent (Please refer [`Clusters::Agents::FilterAuthorizationsService`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/clusters/agents/filter_authorizations_service.rb) for more details), this relationship aren't recorded. This process happens in [`Deployments::CreateForBuildService`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/deployments/create_for_build_service.rb). The database table scheme is: - -```plaintext -agent_deployments: - - deployment_id (bigint/FK/NOT NULL/Unique) - - agent_id (bigint/FK/NOT NULL) - - kubernetes_namespace (character varying(255)/NOT NULL) -``` +Users can explicitly set a GitLab Agent For Kubernetes to a GitLab Environment in setting UI. +Frontend will use this associated agent for authenticating/authorizing the user access, which is described in a latter section. -To idenfity an associated agent for a specific environment, `environment.last_deployment.agent` can be used in Rails. +We need to adjust the `read_cluster_agent` permission in DeclarivePolicy for supporting agents shared by an external project (also known as the Agent management project). ### Fetch resources through `user_access` -When user visits an environment page, GitLab frontend fetches an environment via GraphQL. Frontend additionally fetches the associated agent-ID and namespace through deployment relationship, which being tracked by the `agent_deployments` table. +When user visits an environment page, GitLab frontend fetches an environment via GraphQL. Frontend additionally fetches the associated agent-ID and namespace. Here is an example of GraphQL query: @@ -373,12 +277,12 @@ Here is an example of GraphQL query: id environment(name: "<environment-name>") { slug - lastDeployment(status: SUCCESS) { - agent { - id + kubernetesNamespace + clusterAgent { + id + name + project { name - project - kubernetesNamespace } } } @@ -388,12 +292,9 @@ Here is an example of GraphQL query: GitLab frontend authenticate/authorize the user access with [browser cookie](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/master/doc/kubernetes_user_access.md#browser-cookie-on-gitlab-frontend). If the access is forbidden, frontend shows an error message that `You don't have access to an agent that deployed to this environment. Please contact agent administrator if you are allowed in "user_access" in agent config file. See <troubleshooting-doc-link>`. -After the user gained access to the agent, GitLab frontend fetches available API Resource list in the Kubernetes and fetches the resources with the following parameters: +After the user gained access to the agent, GitLab frontend fetches specific Resource kinds (for example, `Deployment`, `Pod`) in the Kubernetes with the following parameters: -- `namespace` ... `#{environment.lastDeployment.agent.kubernetesNamespace}` -- `labels` - - `app.gitlab.com/project_id=#{project.id}` _AND_ - - `app.gitlab.com/environment_slug: #{environment.slug}` +- `namespace` ... `#{environment.kubernetesNamespace}` If no resources are found, this is likely that the users have not embedded these lables into their resources. In this case, frontend shows an warning message `There are no resources found for the environment. Do resources have GitLab preserved labels? See <troubleshooting-doc-link>`. diff --git a/doc/development/ai_features.md b/doc/development/ai_features.md index c46117c4afd..21d5bb97d56 100644 --- a/doc/development/ai_features.md +++ b/doc/development/ai_features.md @@ -84,6 +84,43 @@ For features that use the embedding database, additional setup is needed. 1. Run `gdk reconfigure` 1. Run database migrations to create the embedding database +### Set up GitLab Chat + +1. [Enable Anthropic API features](#configure-anthropic-access). +1. [Enable OpenAI support](#configure-openai-access). +1. [Ensure the embedding database is configured](#set-up-the-embedding-database). +1. Enable feature specific feature flag. + + ```ruby + Feature.enable(:gitlab_duo) + Feature.enable(:tanuki_bot) + Feature.enable(:ai_redis_cache) + ``` + +1. Ensure that your current branch is up-to-date with `master`. +1. To access the GitLab Chat interface, in the lower-left corner of any page, select **Help** and **Ask GitLab Chat**. + +#### Tips for local development + +1. When responses are taking too long to appear in the user interface, consider restarting Sidekiq by running `gdk restart rails-background-jobs`. If that doesn't work, try `gdk kill` and then `gdk start`. +1. Alternatively, bypass Sidekiq entirely and run the chat service syncronously. This can help with debugging errors as GraphQL errors are now available in the network inspector instead of the Sidekiq logs. + +```diff +diff --git a/ee/app/services/llm/chat_service.rb b/ee/app/services/llm/chat_service.rb +index 5fa7ae8a2bc1..5fe996ba0345 100644 +--- a/ee/app/services/llm/chat_service.rb ++++ b/ee/app/services/llm/chat_service.rb +@@ -5,7 +5,7 @@ class ChatService < BaseService + private + + def perform +- worker_perform(user, resource, :chat, options) ++ worker_perform(user, resource, :chat, options.merge(sync: true)) + end + + def valid? +``` + ### Setup for GitLab documentation chat (legacy chat) To populate the embedding database for GitLab chat: diff --git a/doc/development/gems.md b/doc/development/gems.md index d709e4ab223..caff4ea1b03 100644 --- a/doc/development/gems.md +++ b/doc/development/gems.md @@ -23,9 +23,9 @@ is the [lib/](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/) folder. The **lib/** folder is a mix of code that is generic/universal, GitLab-specific, and tightly integrated with the rest of the codebase. -Ask yourself the question: **can this code also be used in a Ruby project other than the current project?**. +Ask yourself the question: **is this code generic or universal that can be done as a separate and small project?**. If the answer is **Yes** you should strongly consider starting with creating a new Gem [in the same repo](#in-the-same-repo) -and eventually evaluate whether to extract it as a separate repository. +and eventually evaluate whether to extract it as a separate repository if its meant to be used by other projects. ## Advantages of using Gems diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md index 02c8ad44033..01b92f3c33a 100644 --- a/doc/development/testing_guide/best_practices.md +++ b/doc/development/testing_guide/best_practices.md @@ -50,6 +50,32 @@ bundle exec guard When using spring and guard together, use `SPRING=1 bundle exec guard` instead to make use of spring. +### General guidelines + +- Use a single, top-level `RSpec.describe ClassName` block. +- Use `.method` to describe class methods and `#method` to describe instance + methods. +- Use `context` to test branching logic (`RSpec/AvoidConditionalStatements` Rubocop Cop - [MR](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117152)). +- Try to match the ordering of tests to the ordering in the class. +- Try to follow the [Four-Phase Test](https://thoughtbot.com/blog/four-phase-test) pattern, using newlines + to separate phases. +- Use `Gitlab.config.gitlab.host` rather than hard coding `'localhost'`. +- Don't assert against the absolute value of a sequence-generated attribute (see + [Gotchas](../gotchas.md#do-not-assert-against-the-absolute-value-of-a-sequence-generated-attribute)). +- Avoid using `expect_any_instance_of` or `allow_any_instance_of` (see + [Gotchas](../gotchas.md#avoid-using-expect_any_instance_of-or-allow_any_instance_of-in-rspec)). +- Don't supply the `:each` argument to hooks because it's the default. +- On `before` and `after` hooks, prefer it scoped to `:context` over `:all`. +- When using `evaluate_script("$('.js-foo').testSomething()")` (or `execute_script`) which acts on a given element, + use a Capybara matcher beforehand (such as `find('.js-foo')`) to ensure the element actually exists. +- Use `focus: true` to isolate parts of the specs you want to run. +- Use [`:aggregate_failures`](https://rspec.info/features/3-12/rspec-core/expectation-framework-integration/aggregating-failures/) when there is more than one expectation in a test. +- For [empty test description blocks](https://github.com/rubocop-hq/rspec-style-guide#it-and-specify), use `specify` rather than `it do` if the test is self-explanatory. +- Use `non_existing_record_id`/`non_existing_record_iid`/`non_existing_record_access_level` + when you need an ID/IID/access level that doesn't actually exist. Using 123, 1234, + or even 999 is brittle as these IDs could actually exist in the database in the + context of a CI run. + ### Eager loading the application code By default, the application code: @@ -132,9 +158,44 @@ We should reduce test dependencies, and avoiding capabilities also reduces the amount of set-up needed. `:js` is particularly important to avoid. This must only be used if the feature -test requires JavaScript reactivity in the browser. Using a headless +test requires JavaScript reactivity in the browser (e.g. clicking a Vue.js component). Using a headless browser is much slower than parsing the HTML response from the app. +#### Profiling: see where your test spend its time + +[`rspec-stackprof`](https://github.com/dkhroad/rspec-stackprof) can be used to generate a flame graph that shows you where you test spend its time. + +The gem generates a JSON report that we can upload to <https://www.speedscope.app> for an interactive visualization. + +##### Installation + +`stackprof` gem is [already installed with GitLab](https://gitlab.com/gitlab-org/gitlab/-/blob/695fcee0c5541b4ead0a90eb9b8bf0b69bee796c/Gemfile#L487), and we also have a script available that generates the JSON report (`bin/rspec-stackprof`). + +```shell +# Optional: install the `speedscope` package to easily upload the JSON report to https://www.speedscope.app +npm install -g speedscope +``` + +##### Generate the JSON report + +```shell +bin/rspec-stackprof --speedscope=true <your_slow_spec> +# There will be the name of the report displayed when the script ends. + +# Upload the JSON report to speedscope.app +speedscope tmp/<your-json-report>.json +``` + +##### How to interpret the flamegraph + +Below are some useful tips to interpret and navigate the flamegraph: + +- There are [several views available](https://github.com/jlfwong/speedscope#views) for the flamegraph. `Left Heavy` is particularly useful when there are a lot of function calls (e.g. feature specs). +- You can zoom in or out! See [the navigation documentation](https://github.com/jlfwong/speedscope#navigation) +- If you are working on a slow feature test, search for `Capybara::DSL#` in the search to see the capybara actions that are made, and how long they take! + +See [#414929](https://gitlab.com/gitlab-org/gitlab/-/issues/414929#note_1425239887) or [#375004](https://gitlab.com/gitlab-org/gitlab/-/issues/375004#note_1109867718) for some analysis examples. + #### Optimize factory usage A common cause of slow tests is excessive creation of objects, and thus @@ -240,9 +301,21 @@ There are various ways to create objects and store them in variables in your tes - `let` lazily creates the object. It isn't created until the object is called. `let` is generally inefficient as it creates a new object for every example. `let` is fine for simple values. However, more efficient variants of `let` are best when dealing with database models such as factories. - `let_it_be_with_refind` works similar to `let_it_be_with_reload`, but the [former calls `ActiveRecord::Base#find`](https://github.com/test-prof/test-prof/blob/936b29f87b36f88a134e064aa6d8ade143ae7a13/lib/test_prof/ext/active_record_refind.rb#L15) instead of `ActiveRecord::Base#reload`. `reload` is usually faster than `refind`. - `let_it_be_with_reload` creates an object one time for all examples in the same context, but after each example, the database changes are rolled back, and `object.reload` will be called to restore the object to its original state. This means you can make changes to the object before or during an example. However, there are cases where [state leaks across other models](https://github.com/test-prof/test-prof/blob/master/docs/recipes/let_it_be.md#state-leakage-detection) can occur. In these cases, `let` may be an easier option, especially if only a few examples exist. -- `let_it_be` creates an immutable object one time for all of the examples in the same context. This is a great alternative to `let` and `let!` for objects that do not need to change from one example to another. Using `let_it_be` can dramatically speed up tests that create database models. See <https://github.com/test-prof/test-prof/blob/master/docs/recipes/let_it_be.md#let-it-be> for more details and examples. +- `let_it_be` creates an object one time for all of the examples in the same context. This is a great alternative to `let` and `let!` for objects that do not need to change from one example to another. Using `let_it_be` can dramatically speed up tests that create database models. See <https://github.com/test-prof/test-prof/blob/master/docs/recipes/let_it_be.md#let-it-be> for more details and examples. -`let_it_be` is the most optimized option since it instantiates an object once and does not change it. If you find yourself needing `let` instead of `let_it_be`, try `let_it_be_with_reload`. +Pro-tip: When writing tests, it is best to consider the objects inside a `let_it_be` as **immutable**, as there are some important caveats when modifying objects inside a `let_it_be` declaration ([1](https://github.com/test-prof/test-prof/blob/master/docs/recipes/let_it_be.md#database-is-rolled-back-to-a-pristine-state-but-the-objects-are-not), [2](https://github.com/test-prof/test-prof/blob/master/docs/recipes/let_it_be.md#modifiers)). To make your `let_it_be` objects immutable, consider using `.freeze`: + +```shell +# Before +let_it_be(:namespace) { create_default(:namespace) + +# After +let_it_be(:namespace) { create_default(:namespace).freeze +``` + +See <https://github.com/test-prof/test-prof/blob/master/docs/recipes/let_it_be.md#state-leakage-detection> for more information on `let_it_be` freezing. + +`let_it_be` is the most optimized option since it instantiates an object once and shares its instance across examples. If you find yourself needing `let` instead of `let_it_be`, try `let_it_be_with_reload`. ```ruby # Old @@ -336,6 +409,35 @@ NOTE: Refrain from using this stub helper if the test code relies on persisting `project_authorizations` or `Member` records. Use `Project#add_member` or `Group#add_member` instead. +#### Additional profiling metrics + +We can use the `rspec_profiling` gem to diagnose, for instance, the number of SQL queries we're making when running a test. + +This could be caused by some application side SQL queries **triggered by a test that could mock parts that are not under test** (e.g. [!123810](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123810)). + +[See the instructions in the performance docs](../performance.md#rspec-profiling). + +#### Troubleshoot slow feature test + +A slow feature test can generally be optimized the same way as any other test. However, there are some specific techniques that can make the troubleshooting session more fruitful. + +##### See what the feature test is doing in the UI + +```shell +# Before +bin/rspec ./spec/features/admin/admin_settings_spec.rb:992 + +# After +WEBDRIVER_HEADLESS=0 bin/rspec ./spec/features/admin/admin_settings_spec.rb:992 +``` + +See [Run `:js` spec in a visible browser](#run-js-spec-in-a-visible-browser) for more info. + +##### Search for `Capybara::DSL#` when using profiling + +<!-- TODO: Add the search keywords --> +When using [`stackprof` flamegraphs](#profiling-see-where-your-test-spend-its-time), search for `Capybara::DSL#` in the search to see the capybara actions that are made, and how long they take! + #### Identify slow tests Running a spec with profiling is a good way to start optimizing a spec. This can @@ -437,32 +539,6 @@ performance gains. When combining tests, consider using `:aggregate_failures`, so that the full results are available, and not just the first failure. -### General guidelines - -- Use a single, top-level `RSpec.describe ClassName` block. -- Use `.method` to describe class methods and `#method` to describe instance - methods. -- Use `context` to test branching logic. -- Try to match the ordering of tests to the ordering in the class. -- Try to follow the [Four-Phase Test](https://thoughtbot.com/blog/four-phase-test) pattern, using newlines - to separate phases. -- Use `Gitlab.config.gitlab.host` rather than hard coding `'localhost'` -- Don't assert against the absolute value of a sequence-generated attribute (see - [Gotchas](../gotchas.md#do-not-assert-against-the-absolute-value-of-a-sequence-generated-attribute)). -- Avoid using `expect_any_instance_of` or `allow_any_instance_of` (see - [Gotchas](../gotchas.md#avoid-using-expect_any_instance_of-or-allow_any_instance_of-in-rspec)). -- Don't supply the `:each` argument to hooks because it's the default. -- On `before` and `after` hooks, prefer it scoped to `:context` over `:all` -- When using `evaluate_script("$('.js-foo').testSomething()")` (or `execute_script`) which acts on a given element, - use a Capybara matcher beforehand (such as `find('.js-foo')`) to ensure the element actually exists. -- Use `focus: true` to isolate parts of the specs you want to run. -- Use [`:aggregate_failures`](https://rspec.info/features/3-12/rspec-core/expectation-framework-integration/aggregating-failures/) when there is more than one expectation in a test. -- For [empty test description blocks](https://github.com/rubocop-hq/rspec-style-guide#it-and-specify), use `specify` rather than `it do` if the test is self-explanatory. -- Use `non_existing_record_id`/`non_existing_record_iid`/`non_existing_record_access_level` - when you need an ID/IID/access level that doesn't actually exists. Using 123, 1234, - or even 999 is brittle as these IDs could actually exist in the database in the - context of a CI run. - ### Feature category metadata You must [set feature category metadata for each RSpec example](../feature_categorization/index.md#rspec-examples). diff --git a/doc/user/packages/composer_repository/index.md b/doc/user/packages/composer_repository/index.md index b990cf1f09b..c9d09e42532 100644 --- a/doc/user/packages/composer_repository/index.md +++ b/doc/user/packages/composer_repository/index.md @@ -142,7 +142,7 @@ To install a package: - Connect to the Package Registry for your group: ```shell - composer config repositories.<group_id> composer https://gitlab.example.com/api/v4/group/<group_id>/-/packages/composer/ + composer config repositories.<group_id> composer https://gitlab.example.com/api/v4/group/<group_id>/-/packages/composer/packages.json ``` - Set the required package version: @@ -159,7 +159,7 @@ To install a package: "repositories": { "<group_id>": { "type": "composer", - "url": "https://gitlab.example.com/api/v4/group/<group_id>/-/packages/composer/" + "url": "https://gitlab.example.com/api/v4/group/<group_id>/-/packages/composer/packages.json" }, ... }, @@ -243,7 +243,7 @@ To install a package: { ... "repositories": [ - { "type": "composer", "url": "https://gitlab.example.com/api/v4/group/<group_id>/-/packages/composer/" } + { "type": "composer", "url": "https://gitlab.example.com/api/v4/group/<group_id>/-/packages/composer/packages.json" } ], "config": { ... diff --git a/doc/user/project/members/index.md b/doc/user/project/members/index.md index 7a1d9d6e6e3..c67e40b75d6 100644 --- a/doc/user/project/members/index.md +++ b/doc/user/project/members/index.md @@ -69,7 +69,7 @@ If a user is: ### Membership and visibility rights -Depending on their membership type, members of groups or projects are granted different visibility levels +Depending on their membership type, members of groups or projects are granted different [visibility levels](../../../user/public_access.md) and rights into the group or project. | Action | Direct group member | Inherited group member | Direct shared group member | Inherited shared group member | diff --git a/doc/user/public_access.md b/doc/user/public_access.md index 002cb97dd93..4fdbde1f4f1 100644 --- a/doc/user/public_access.md +++ b/doc/user/public_access.md @@ -7,18 +7,24 @@ type: reference # Project and group visibility **(FREE)** -A project in GitLab can be private, internal, or public. +Projects and groups in GitLab can be private, internal, or public. + +The visibility level of the group or project has no influence on whether members within the group or project can see each other. +A group or project is an object to allow collaborative work. This is only possible if all members know about each other. + +Group or project members can see all members of the group or project they belong to. +Group or project owners can see the origin of membership (the original group or project) of all members. ## Private projects and groups -For private projects, only project members can: +For private projects, only members of the private project or group can: - Clone the project. - View the public access directory (`/public`). Users with the Guest role cannot clone the project. -Private groups can have private subgroups only. +Private groups can have only private subgroups. ## Internal projects and groups **(FREE SELF)** @@ -27,6 +33,8 @@ For internal projects, **any authenticated user**, including users with the Gues - Clone the project. - View the public access directory (`/public`). +Only internal members can view internal content. + [External users](admin_area/external_users.md) cannot clone the project. Internal groups can have internal or private subgroups. |