Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-12-01 18:14:38 +00:00
parent c3ddbeb162
commit 07cbb41fee
53 changed files with 845 additions and 226 deletions

View File

@ -73,7 +73,6 @@ Style/RedundantReturn:
- 'ee/app/serializers/vulnerabilities/merge_request_link_entity.rb'
- 'ee/app/services/audit_events/streaming/headers/base.rb'
- 'ee/app/services/ee/post_receive_service.rb'
- 'ee/app/services/gitlab_subscriptions/user_add_on_assignments/create_service.rb'
- 'ee/app/services/security/orchestration/assign_service.rb'
- 'ee/app/services/vulnerabilities/manually_create_service.rb'
- 'ee/app/workers/ee/repository_check/batch_worker.rb'

View File

@ -72,11 +72,20 @@ export default Node.create({
addInputRules() {
const { editor } = this;
const { assetResolver } = this.options;
const referenceInputRegex = /(?:^|\s)([\w/]*([!&#])\d+(\+?s?))(?:\s|\n)/m;
const referenceInputRegex = /(?:^|\s)([\w/]*([#!&%$@~]|\[vulnerability:)[\w.]+(\+?s?\]?))(?:\s|\n)/m;
const referenceTypes = {
'#': 'issue',
'!': 'merge_request',
'&': 'epic',
'%': 'milestone',
$: 'snippet',
'@': 'user',
'~': 'label',
'[vulnerability:': 'vulnerability',
};
const nodeTypes = {
label: editor.schema.nodes.referenceLabel,
default: editor.schema.nodes.reference,
};
return [
@ -91,22 +100,26 @@ export default Node.create({
text,
expandedText,
fullyExpandedText,
backgroundColor,
} = await assetResolver.resolveReference(referenceId);
if (!text) return;
let referenceText = text;
if (expansionType === '+') referenceText = expandedText;
if (expansionType === '+s') referenceText = fullyExpandedText;
if (expansionType === '+') referenceText = expandedText || text;
if (expansionType === '+s') referenceText = fullyExpandedText || text;
const position = findReference(editor, referenceId);
if (!position) return;
const nodeType = nodeTypes[referenceType] || nodeTypes.default;
editor.view.dispatch(
editor.state.tr.replaceWith(position, position + referenceId.length, [
this.type.create({
nodeType.create({
referenceType,
originalText: referenceId,
color: backgroundColor,
href,
text: referenceText,
}),

View File

@ -27,10 +27,11 @@ export default class AssetResolver {
if (!a.length) return {};
return {
href: a[0].getAttribute('href'),
text: a[0].textContent,
expandedText: a[1].textContent,
fullyExpandedText: a[2].textContent,
href: a[0]?.getAttribute('href'),
text: a[0]?.textContent,
expandedText: a[1]?.textContent,
fullyExpandedText: a[2]?.textContent,
backgroundColor: a[0]?.firstElementChild?.style.backgroundColor,
};
});

View File

@ -56,7 +56,11 @@ module Import
session[:auth_on_failure_path] = "#{new_project_path}#import_project"
oauth_client.auth_code.authorize_url(
redirect_uri: callback_import_url,
scope: 'repo, user, user:email',
# read:org only required for collaborator import, which is optional,
# but at the time of this OAuth request we do not know which optional
# configuration the user will select because the options are only shown
# after authenticating
scope: 'repo, read:org',
state: state
)
end

View File

@ -79,10 +79,10 @@ class Ability
policy = policy_for(user, subject, **opts.slice(:cache))
# https://gitlab.com/gitlab-org/gitlab/-/issues/421150#note_1638311666
if ability == :read_namespace && Feature.enabled?(:log_read_namespace_usages, Feature.current_request)
if ability.to_sym == :read_namespace && Feature.enabled?(:log_read_namespace_usages, Feature.current_request)
Gitlab::AppLogger.info(
message: 'Ability is in use',
ability: ability,
ability: ability.to_sym,
caller_locations: caller_locations(1, 5).map(&:to_s)
)
end

View File

@ -36,7 +36,7 @@ module Ci
next [] if no_local_dependencies_specified?
next [] unless processable.pipeline_id # we don't have any dependency when creating the pipeline
deps = model_class.where(pipeline_id: processable.pipeline_id).latest
deps = model_class.where(pipeline_id: processable.pipeline_id, partition_id: processable.partition_id).latest
deps = find_dependencies(processable, deps)
from_dependencies(deps).to_a

View File

@ -22,10 +22,37 @@ module Enums
wolfi: 13
}.with_indifferent_access.freeze
DEPENDENCY_SCANNING_PURL_TYPES = %w[
composer
conan
gem
golang
maven
npm
nuget
pypi
].freeze
CONTAINER_SCANNING_PURL_TYPES = %w[
apk
rpm
deb
cbl-mariner
wolfi
].freeze
def self.component_types
COMPONENT_TYPES
end
def self.dependency_scanning_purl_type?(purl_type)
DEPENDENCY_SCANNING_PURL_TYPES.include?(purl_type)
end
def self.container_scanning_purl_type?(purl_type)
CONTAINER_SCANNING_PURL_TYPES.include?(purl_type)
end
def self.purl_types
# return 0 by default if the purl_type is not found, to prevent
# consumers from producing invalid SQL caused by null entries

View File

@ -1278,15 +1278,6 @@ class Repository
.map(&:to_h)
end
def filter_generated_files(revision, paths)
# NOTE: We should still support linguist-generated override for GitHub compatibility,
# but `gitlab-*` prefixed overrides would give us a better control moving forward.
generated_files = get_file_attributes(revision, paths, %w[gitlab-generated linguist-generated])
.pluck(:path)
paths - generated_files
end
def object_format
return unless exists?

View File

@ -77,7 +77,8 @@ module Users
vsd_feedback_banner: 75, # EE-only
security_policy_protected_branch_modification: 76, # EE-only
vulnerability_report_grouping: 77, # EE-only
new_nav_for_everyone_callout: 78
new_nav_for_everyone_callout: 78,
duo_chat_callout: 79 # EE-only
}
validates :feature_name,

View File

@ -7,19 +7,38 @@ module Ml
@version = params[:version]
@package = params[:package]
@description = params[:description]
@user = params[:user]
end
def execute
@version ||= Ml::IncrementVersionService.new(@model.latest_version.try(:version)).execute
ApplicationRecord.transaction do
@version ||= Ml::IncrementVersionService.new(@model.latest_version.try(:version)).execute
model_version = Ml::ModelVersion.find_or_create!(@model, @version, @package, @description)
package = @package || find_or_create_package(@model.name, @version)
model_version.candidate = ::Ml::CreateCandidateService.new(
@model.default_experiment,
{ model_version: model_version }
).execute
model_version = Ml::ModelVersion.create!(model: @model, project: @model.project, version: @version,
package: package, description: @description)
model_version
model_version.candidate = ::Ml::CreateCandidateService.new(
@model.default_experiment,
{ model_version: model_version }
).execute
model_version
end
end
private
def find_or_create_package(model_name, model_version)
package_params = {
name: model_name,
version: model_version
}
::Packages::MlModel::FindOrCreatePackageService
.new(@model.project, @user, package_params)
.execute
end
end
end

View File

@ -2,7 +2,7 @@
migration_job_name: BackfillFindingIdInVulnerabilities
description: Backfills finding_id column on vulnerabilities table for a proper 1:1 relation
feature_category: vulnerability_management
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/418971
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130058
queued_migration_version: 20231116105945
milestone: 16.4
finalize_after: '2023-12-15'

View File

@ -28,7 +28,7 @@ swap:
e-mail: "email"
emojis: "emoji"
ex: "for example"
file name: "filename"
filename: "file name"
filesystem: "file system"
info: "information"
installation from source: self-compiled installation

View File

@ -74,6 +74,7 @@ In the following table, you can see:
| [Сross-project pipelines with artifacts dependencies](../../ci/yaml/index.md#needsproject) | GitLab 16.7 and later |
| [Feature flag related issues](../../operations/feature_flags.md#feature-flag-related-issues) | GitLab 16.7 and later |
| [Merged results pipelines](../../ci/pipelines/merged_results_pipelines.md) | GitLab 16.7 and later |
| [CI/CD for GitHub](../../ci/ci_cd_for_external_repos/github_integration.md) | GitLab 16.7 and later |
### Enable registration features

View File

@ -65,7 +65,9 @@ Example response:
"parent_ids": [
"6104942438c14ec7bd21c6cd5bd995272b3faff6"
],
"web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746"
"web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746",
"trailers": {},
"extended_trailers": {}
},
{
"id": "6104942438c14ec7bd21c6cd5bd995272b3faff6",
@ -76,11 +78,13 @@ Example response:
"committer_name": "ExampleName",
"committer_email": "user@example.com",
"created_at": "2021-09-20T09:06:12.201+00:00",
"message": "Sanitize for network graph",
"message": "Sanitize for network graph\nCc: John Doe <johndoe@gitlab.com>\nCc: Jane Doe <janedoe@gitlab.com>",
"parent_ids": [
"ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba"
],
"web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746"
"web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746",
"trailers": { "Cc": "Jane Doe <janedoe@gitlab.com>" },
"extended_trailers": { "Cc": ["John Doe <johndoe@gitlab.com>", "Jane Doe <janedoe@gitlab.com>"] }
}
]
```

View File

@ -9513,6 +9513,30 @@ The edge type for [`CiStage`](#cistage).
| <a id="cistageedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="cistageedgenode"></a>`node` | [`CiStage`](#cistage) | The item at the end of the edge. |
#### `CiSubscriptionsProjectConnection`
The connection type for [`CiSubscriptionsProject`](#cisubscriptionsproject).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="cisubscriptionsprojectconnectioncount"></a>`count` | [`Int!`](#int) | Total count of collection. |
| <a id="cisubscriptionsprojectconnectionedges"></a>`edges` | [`[CiSubscriptionsProjectEdge]`](#cisubscriptionsprojectedge) | A list of edges. |
| <a id="cisubscriptionsprojectconnectionnodes"></a>`nodes` | [`[CiSubscriptionsProject]`](#cisubscriptionsproject) | A list of nodes. |
| <a id="cisubscriptionsprojectconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
#### `CiSubscriptionsProjectEdge`
The edge type for [`CiSubscriptionsProject`](#cisubscriptionsproject).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="cisubscriptionsprojectedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="cisubscriptionsprojectedgenode"></a>`node` | [`CiSubscriptionsProject`](#cisubscriptionsproject) | The item at the end of the edge. |
#### `ClusterAgentActivityEventConnection`
The connection type for [`ClusterAgentActivityEvent`](#clusteragentactivityevent).
@ -23718,6 +23742,8 @@ Represents vulnerability finding of a security report on the pipeline.
| <a id="projectcicdsettings"></a>`ciCdSettings` | [`ProjectCiCdSetting`](#projectcicdsetting) | CI/CD settings for the project. |
| <a id="projectciconfigpathordefault"></a>`ciConfigPathOrDefault` | [`String!`](#string) | Path of the CI configuration file. |
| <a id="projectcijobtokenscope"></a>`ciJobTokenScope` | [`CiJobTokenScopeType`](#cijobtokenscopetype) | The CI Job Tokens scope of access. |
| <a id="projectcisubscribedprojects"></a>`ciSubscribedProjects` | [`CiSubscriptionsProjectConnection`](#cisubscriptionsprojectconnection) | Triggers a new pipeline in the downstream project when a pipeline successfullycompletes on the(upstream) project. (see [Connections](#connections)) |
| <a id="projectcisubscriptionsprojects"></a>`ciSubscriptionsProjects` | [`CiSubscriptionsProjectConnection`](#cisubscriptionsprojectconnection) | Triggers a new pipeline in the(downstream) project when a pipeline successfullycompletes on the upstream project. (see [Connections](#connections)) |
| <a id="projectcodecoveragesummary"></a>`codeCoverageSummary` | [`CodeCoverageSummary`](#codecoveragesummary) | Code coverage summary associated with the project. |
| <a id="projectcomplianceframeworks"></a>`complianceFrameworks` | [`ComplianceFrameworkConnection`](#complianceframeworkconnection) | Compliance frameworks associated with the project. (see [Connections](#connections)) |
| <a id="projectcontainerexpirationpolicy"></a>`containerExpirationPolicy` | [`ContainerExpirationPolicy`](#containerexpirationpolicy) | Container expiration policy of the project. |
@ -31056,6 +31082,7 @@ Name of the feature that the callout is for.
| <a id="usercalloutfeaturenameenumci_deprecation_warning_for_types_keyword"></a>`CI_DEPRECATION_WARNING_FOR_TYPES_KEYWORD` | Callout feature name for ci_deprecation_warning_for_types_keyword. |
| <a id="usercalloutfeaturenameenumcloud_licensing_subscription_activation_banner"></a>`CLOUD_LICENSING_SUBSCRIPTION_ACTIVATION_BANNER` | Callout feature name for cloud_licensing_subscription_activation_banner. |
| <a id="usercalloutfeaturenameenumcluster_security_warning"></a>`CLUSTER_SECURITY_WARNING` | Callout feature name for cluster_security_warning. |
| <a id="usercalloutfeaturenameenumduo_chat_callout"></a>`DUO_CHAT_CALLOUT` | Callout feature name for duo_chat_callout. |
| <a id="usercalloutfeaturenameenumeoa_bronze_plan_banner"></a>`EOA_BRONZE_PLAN_BANNER` | Callout feature name for eoa_bronze_plan_banner. |
| <a id="usercalloutfeaturenameenumfeature_flags_new_version"></a>`FEATURE_FLAGS_NEW_VERSION` | Callout feature name for feature_flags_new_version. |
| <a id="usercalloutfeaturenameenumgcp_signup_offer"></a>`GCP_SIGNUP_OFFER` | Callout feature name for gcp_signup_offer. |

View File

@ -108,9 +108,9 @@ The first 2-3 quarters are required to define a general split of data, and build
The purpose is to perform a targeted decomposition of `users` and `projects`, because `projects` will be stored locally in the Cell.
1. **User can create files in repository**
1. **User can create Project with a README file**
The purpose is to allow `users` to create files in a repository.
The purpose is to allow `users` to create README files in a project.
1. **User can change profile avatar that is shared in cluster.**
@ -284,7 +284,7 @@ It is expected that initial iterations will be rather slow, because they require
- Data access layer: Data access layer.
- Routing: User can use single domain to interact with many Cells.
- Cell deployment: Extend GitLab Dedicated to support GCP.
- Essential workflows: User can create files in repository.
- Essential workflows: User can create Project with a README file.
- Essential workflows: User can push to Git repository.
- Essential workflows: User can run CI pipeline.
- Essential workflows: Instance-wide settings are shared across cluster.

View File

@ -289,7 +289,7 @@ Each file table should include a short summary of changes that will read out:
The summary of the table content can be placed either within `<caption>` element, or before the table within an element referred as `aria-describedby`.
See <abbr>WAI</abbr> (Web Accessibility Initiative) for more information on both approaches:
- [Nesting summary inside the <caption> element](https://www.w3.org/WAI/tutorials/tables/caption-summary/#nesting-summary-inside-the-caption-element)
- [Nesting summary inside the `<caption>` element](https://www.w3.org/WAI/tutorials/tables/caption-summary/#nesting-summary-inside-the-caption-element)
- [Using aria-describedby to provide a table summary](https://www.w3.org/WAI/tutorials/tables/caption-summary/#using-aria-describedby-to-provide-a-table-summary)
However, if such a structure will compromise other functional aspects of displaying a diff,

View File

@ -15,9 +15,8 @@ GitLab CI/CD can be used with Bitbucket Cloud by:
To use GitLab CI/CD with a Bitbucket Cloud repository:
1. In GitLab, create a project:
1. On the left sidebar, select **Search or go to**.
1. Select **View all my projects**.
1. On the right of the page, select **New project**.
1. On the left sidebar, at the top, select **Create new** (**{plus}**) and **New project/repository**.
1. Select **Run CI/CD for external repository**.
1. Select **Repository by URL**.
1. Fill in the fields with information from the repository in Bitbucket:

View File

@ -34,9 +34,7 @@ repositories:
`repo` and `admin:repo_hook` so that GitLab can access your project,
update commit statuses, and create a web hook to notify GitLab of new commits.
1. In GitLab, create a project:
1. On the left sidebar, select **Search or go to**.
1. Select **View all my projects**.
1. On the right of the page, select **New project**.
1. On the left sidebar, at the top, select **Create new** (**{plus}**) and **New project/repository**.
1. Select **Run CI/CD for external repository**.
1. Select **GitHub**.
1. For **Personal access token**, paste the token.
@ -63,9 +61,7 @@ To manually enable GitLab CI/CD for your repository:
1. Enter a **Token description** and update the scope to allow
`repo` so that GitLab can access your project and update commit statuses.
1. In GitLab, create a project:
1. On the left sidebar, select **Search or go to**.
1. Select **View all my projects**.
1. Select **New project**.
1. On the left sidebar, at the top, select **Create new** (**{plus}**) and **New project/repository**.
1. Select **Run CI/CD for external repository** and **Repository by URL**.
1. In the **Git repository URL** field, enter the HTTPS URL for your GitHub repository.
If your project is private, use the personal access token you just created for authentication.

View File

@ -24,9 +24,7 @@ snippets disabled. These features
To connect to an external repository:
1. On the left sidebar, select **Search or go to**.
1. Select **View all my projects**.
1. Select **New project**.
1. On the left sidebar, at the top, select **Create new** (**{plus}**) and **New project/repository**.
1. Select **Run CI/CD for external repository**.
1. Select **GitHub** or **Repository by URL**.
1. Complete the fields.

View File

@ -39,18 +39,12 @@ For the first step here, you create a demo application from a project template.
Use a GitLab project template to get started. As the name suggests, these projects provide a
bare-bones application built on some well-known frameworks.
1. In GitLab, select the plus icon (**{plus-square}**) at the top of the navigation bar, and select
**New project**.
1. In GitLab on the left sidebar, at the top, select **Create new** (**{plus}**) and **New project/repository**.
1. Select **Create from template**, where you can choose from a Ruby on Rails, Spring, or
NodeJS Express project. For this guide, use the Ruby on Rails template.
![Select project template](img/rails-template.png)
1. Give your project a name. In this example, it's named `ecs-demo`. Make it public so that you can
take advantage of the features available in the
[GitLab Ultimate plan](https://about.gitlab.com/pricing/).
1. Select **Create project**.
Now that you created a demo project, you must containerize the application and push it to the
@ -63,8 +57,8 @@ provide a containerized application image during the infrastructure build. To do
GitLab [Auto Build](../../../topics/autodevops/stages.md#auto-build)
and [Container Registry](../../../user/packages/container_registry/index.md).
1. Go to **ecs-demo** project on GitLab.
1. Select **Setup up CI/CD**. It brings you to a `.gitlab-ci.yml`
1. On the left sidebar, select **Search or go to** and find your `ecs-demo` project.
1. Select **Set up CI/CD**. It brings you to a `.gitlab-ci.yml`
creation form.
1. Copy and paste the following content into the empty `.gitlab-ci.yml`. This defines
a pipeline for continuous deployment to ECS.
@ -184,7 +178,7 @@ Now, the demo application is accessible from the internet.
In this guide, HTTPS/SSL is **not** configured. You can access to the application through HTTP only
(for example, `http://<ec2-ipv4-address>`).
## Setup Continuous Deployment from GitLab
## Set up Continuous Deployment from GitLab
Now that you have an application running on ECS, you can set up continuous deployment from GitLab.
@ -213,7 +207,7 @@ Do not share the secret access key in a public place. You must save it in a secu
You can register the access information in [GitLab CI/CD Variables](../../variables/index.md).
These variables are injected into the pipeline jobs and can access the ECS API.
1. Go to **ecs-demo** project on GitLab.
1. On the left sidebar, select **Search or go to** and find your `ecs-demo` project.
1. Go to **Settings > CI/CD > Variables**.
1. Select **Add Variable** and set the following key-value pairs.
@ -230,8 +224,8 @@ These variables are injected into the pipeline jobs and can access the ECS API.
Change a file in the project and see if it's reflected in the demo application on ECS:
1. Go to **ecs-demo** project on GitLab.
1. Open the file at **app > views > welcome > `index.html.erb`**.
1. On the left sidebar, select **Search or go to** and find your `ecs-demo` project.
1. Open the `app/views/welcome/index.html.erb` file.
1. Select **Edit**.
1. Change the text to `You're on ECS!`.
1. Select **Commit Changes**. This automatically triggers a new pipeline. Wait until it finishes.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -313,13 +313,13 @@ ensure-job-added:
exit 1
fi
# If we are tagging a release with a specific convention ("v" + number) and all
# previous checks succeeded, we proceed with creating a release automatically.
# If we are tagging a release with a semantic version and all previous checks succeeded,
# we proceed with creating a release automatically.
create-release:
stage: release
image: registry.gitlab.com/gitlab-org/release-cli:latest
rules:
- if: $CI_COMMIT_TAG =~ /^v\d+/
- if: $CI_COMMIT_TAG =~ /\d+/
script: echo "Creating release $CI_COMMIT_TAG"
release:
tag_name: $CI_COMMIT_TAG

View File

@ -150,7 +150,7 @@ For examples of others who have implemented GitLab CI/CD, see:
- [Test all the things in GitLab CI with Docker by example](https://about.gitlab.com/blog/2018/02/05/test-all-the-things-gitlab-ci-docker-examples/)
- [A Craftsman looks at continuous integration](https://about.gitlab.com/blog/2018/01/17/craftsman-looks-at-continuous-integration/)
- [Go tools and GitLab: How to do continuous integration like a boss](https://about.gitlab.com/blog/2017/11/27/go-tools-and-gitlab-how-to-do-continuous-integration-like-a-boss/)
- [GitBot automating boring Git operations with CI](https://about.gitlab.com/blog/2017/11/02/automating-boring-git-operations-gitlab-ci/)
- [GitBot - automating boring Git operations with CI](https://about.gitlab.com/blog/2017/11/02/automating-boring-git-operations-gitlab-ci/)
- [How to use GitLab CI for Vue.js](https://about.gitlab.com/blog/2017/09/12/vuejs-app-gitlab/)
- Video: [GitLab CI/CD Deep Dive](https://youtu.be/pBe4t1CD8Fc?t=195)
- [Dockerizing GitLab Review Apps](https://about.gitlab.com/blog/2017/07/11/dockerizing-review-apps/)

View File

@ -45,7 +45,11 @@ The **Lint** tab is replaced with the **Validate** tab in GitLab 15.3. The lint
in a successful [pipeline simulation](#simulate-a-cicd-pipeline).
To test the validity of your GitLab CI/CD configuration before committing the changes,
you can use the CI lint tool. To access it, go to **Build > Pipeline editor** and select the **Lint** tab.
you can use the CI lint tool:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Pipeline editor**.
1. Select the **Lint** tab.
This tool checks for syntax and logical errors but goes into more detail than the
automatic [validation](#validate-ci-configuration) in the editor.

View File

@ -671,9 +671,7 @@ the ones defined in the upstream project take precedence.
### Pass dotenv variables created in a job **(PREMIUM ALL)**
You can pass variables to a downstream job with [`dotenv` variable inheritance](../variables/index.md#pass-an-environment-variable-to-another-job)
and [`needs:project`](../yaml/index.md#needsproject). These variables are only available in
the script of the job and can't be used to configure it, for example with `rules` or `artifact:paths`.
You can pass variables to a downstream pipeline with [`dotenv` variable inheritance](../variables/index.md#pass-an-environment-variable-to-another-job).
For example, in a [multi-project pipeline](#multi-project-pipelines):

View File

@ -135,11 +135,11 @@ be extended for dynamic environments, but a few extra steps are required:
1. The `browser_performance` job should run after the dynamic environment has started.
1. In the `review` job:
1. Generate a URL list file with the dynamic URL.
1. Save the file as an artifact, for example with `echo $CI_ENVIRONMENT_URL > environment_url.txt`
in your job's `script`.
1. Pass the list as the URL environment variable (which can be a URL or a file containing URLs)
to the `browser_performance` job.
1. Generate a URL list file with the dynamic URL.
1. Save the file as an artifact, for example with `echo $CI_ENVIRONMENT_URL > environment_url.txt`
in your job's `script`.
1. Pass the list as the URL environment variable (which can be a URL or a file containing URLs)
to the `browser_performance` job.
1. You can now run the sitespeed.io container against the desired hostname and
paths.

View File

@ -520,15 +520,15 @@ Code Quality functionality can be extended by using Code Climate
For example, to use the [SonarJava analyzer](https://docs.codeclimate.com/docs/sonar-java):
1. Add a file named `.codeclimate.yml` to the root of your repository
1. Add to the `.codeclimate.yml` the [enablement code](https://docs.codeclimate.com/docs/sonar-java#enable-the-plugin)
for the plugin to the root of your repository:
1. Add the [enablement code](https://docs.codeclimate.com/docs/sonar-java#enable-the-plugin)
for the plugin to the root of your repository to the `.codeclimate.yml` file:
```yaml
version: "2"
plugins:
sonar-java:
enabled: true
```
```yaml
version: "2"
plugins:
sonar-java:
enabled: true
```
This adds SonarJava to the `plugins:` section of the
[default `.codeclimate.yml`](https://gitlab.com/gitlab-org/ci-cd/codequality/-/blob/master/codeclimate_defaults/.codeclimate.yml.template)

View File

@ -294,9 +294,18 @@ Use **check out** as a verb. For the Git command, use `checkout`.
- Use `git checkout` to check out a branch locally.
- Check out the files you want to edit.
## CI, CD
When talking about GitLab features, use **CI/CD**. Do not use **CI** or **CD** alone.
## CI/CD
CI/CD is always uppercase. No need to spell it out on first use.
**CI/CD** is always uppercase. No need to spell it out on first use.
You can omit **CI/CD** when the context is clear, especially after the first use. For example:
- Test your code in a **CI/CD pipeline**. Configure the **pipeline** to run for merge requests.
- Store the value in a **CI/CD variable**. Set the **variable** to masked.
## CI/CD minutes
@ -651,6 +660,12 @@ of the fields at once. For example:
Learn more about [documenting multiple fields at once](index.md#documenting-multiple-fields-at-once).
## file name
Use two words for **file name**.
([Vale](../testing.md#vale) rule: [`SubstitutionWarning.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/SubstitutionWarning.yml))
## filter
When you are viewing a list of items, like issues or merge requests, you filter the list by

View File

@ -62,13 +62,13 @@ If your computer doesn't recognize `git` as a command, you must [install Git](..
## Configure Git
To start using Git from your computer, you must enter your credentials
to identify yourself as the author of your work. The username and email address
to identify yourself as the author of your work. The full name and email address
should match the ones you use in GitLab.
1. In your shell, add your user name:
1. In your shell, add your full name:
```shell
git config --global user.name "your_username"
git config --global user.name "John Doe"
```
1. Add your email address:

View File

@ -19,6 +19,8 @@ When SCIM is enabled for a GitLab group, membership of that group is synchronize
The [internal GitLab group SCIM API](../../../development/internal_api/index.md#group-scim-api) implements part of [the RFC7644 protocol](https://www.rfc-editor.org/rfc/rfc7644).
Identity providers can use the [internal GitLab group SCIM API](../../../development/internal_api/index.md#group-scim-api) to develop a SCIM app.
To set up SCIM on GitLab self-managed, see [Configure SCIM for self-managed GitLab instances](../../../administration/settings/scim_setup.md).
## Configure GitLab
Prerequisites:

View File

@ -5,28 +5,14 @@ module Gitlab
module Reports
module Sbom
class Source
include SourceHelper
attr_reader :source_type, :data
def initialize(type:, data:)
@source_type = type
@data = data
end
def source_file_path
data.dig('source_file', 'path')
end
def input_file_path
data.dig('input_file', 'path')
end
def packager
data.dig('package_manager', 'name')
end
def language
data.dig('language', 'name')
end
end
end
end

View File

@ -0,0 +1,43 @@
# frozen_string_literal: true
module Gitlab
module Ci
module Reports
module Sbom
module SourceHelper
def source_file_path
data.dig('source_file', 'path')
end
def input_file_path
data.dig('input_file', 'path')
end
def packager
data.dig('package_manager', 'name')
end
def language
data.dig('language', 'name')
end
def image_name
data.dig('image', 'name')
end
def image_tag
data.dig('image', 'tag')
end
def operating_system_name
data.dig('operating_system', 'name')
end
def operating_system_version
data.dig('operating_system', 'version')
end
end
end
end
end
end

View File

@ -33,6 +33,7 @@ module Gitlab
# The order of this list refers to the priority of the variables
# The variables added later takes priority.
downstream_yaml_variables +
downstream_pipeline_dotenv_variables +
downstream_pipeline_variables +
downstream_pipeline_schedule_variables
end
@ -57,6 +58,13 @@ module Gitlab
build_downstream_variables_from(pipeline_schedule_variables)
end
def downstream_pipeline_dotenv_variables
return [] unless bridge.forward_pipeline_variables?
pipeline_dotenv_variables = bridge.dependency_variables.to_a
build_downstream_variables_from(pipeline_dotenv_variables)
end
def build_downstream_variables_from(variables)
Gitlab::Ci::Variables::Collection.fabricate(variables).flat_map do |item|
if item.raw?

View File

@ -12,6 +12,13 @@ module Gitlab
TAG_REF_PREFIX = "refs/tags/"
BRANCH_REF_PREFIX = "refs/heads/"
# NOTE: We don't use linguist anymore, but we'd still want to support it
# to be backward/GitHub compatible. Using `gitlab-*` prefixed overrides
# going forward would give us a better control and flexibility.
ATTRIBUTE_OVERRIDES = {
generated: %w[gitlab-generated linguist-generated]
}.freeze
CommandError = Class.new(BaseError)
CommitError = Class.new(BaseError)
OSError = Class.new(BaseError)

View File

@ -42,6 +42,16 @@ module Gitlab
options[:straight] = @straight
Gitlab::Git::Diff.between(@repository, @head.id, @base.id, options, *paths)
end
def generated_files
return Set.new unless @base && @head
changed_paths = @repository
.find_changed_paths([Gitlab::Git::DiffTree.new(@base.id, @head.id)])
.map(&:path)
@repository.detect_generated_files(@base.id, changed_paths)
end
end
end
end

View File

@ -1207,6 +1207,7 @@ module Gitlab
gitaly_repository_client
.get_file_attributes(revision, file_paths, attributes)
.attribute_infos
.map(&:to_h)
end
end
@ -1216,6 +1217,16 @@ module Gitlab
end
end
# rubocop: disable CodeReuse/ActiveRecord -- not an active record operation
def detect_generated_files(revision, paths)
return Set.new if paths.blank?
get_file_attributes(revision, paths, Gitlab::Git::ATTRIBUTE_OVERRIDES[:generated])
.pluck(:path)
.to_set
end
# rubocop: enable CodeReuse/ActiveRecord
private
def repository_info_size_megabytes

View File

@ -6690,6 +6690,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
msgid "Ask GitLab Duo"
msgstr ""
msgid "Ask a maintainer to check the import status for more details."
msgstr ""
@ -47769,14 +47772,23 @@ msgstr ""
msgid "TanukiBot|Give feedback"
msgstr ""
msgid "TanukiBot|How to use GitLab"
msgstr ""
msgid "TanukiBot|Source"
msgid_plural "TanukiBot|Sources"
msgstr[0] ""
msgstr[1] ""
msgid "TanukiBot|The issue, epic, or code you're viewing"
msgstr ""
msgid "TanukiBot|There was an error communicating with GitLab Duo Chat. Please try again later."
msgstr ""
msgid "TanukiBot|Use AI to answer questions about things like:"
msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""

View File

@ -3,6 +3,8 @@
require_relative '../../migration_helpers'
require_relative '../../batched_background_migrations_dictionary'
URL_PATTERN = %r{\Ahttps://gitlab\.com/gitlab-org/gitlab/-/merge_requests/\d+\z}
module RuboCop
module Cop
module BackgroundMigration
@ -11,6 +13,7 @@ module RuboCop
include MigrationHelpers
MSG = {
invalid_url: "Invalid `%{key}` url for the dictionary. Please use the following format: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/XXX",
missing_key: "Mandatory key '%{key}' is missing from the dictionary. Please add with an appropriate value.",
missing_dictionary: <<-MESSAGE.delete("\n").squeeze(' ').strip
Missing %{file_name}.
@ -49,6 +52,10 @@ module RuboCop
private
def valid_url?(url)
url.match?(URL_PATTERN)
end
def dictionary_file?(migration_class_name)
File.exist?(dictionary_file_path(migration_class_name))
end
@ -67,6 +74,8 @@ module RuboCop
return [:missing_key, { key: :finalize_after }] unless bbm_dictionary.finalize_after.present?
return [:missing_key, { key: :introduced_by_url }] unless bbm_dictionary.introduced_by_url.present?
return [:invalid_url, { key: :introduced_by_url }] unless valid_url?(bbm_dictionary.introduced_by_url)
end
def rails_root

View File

@ -2,21 +2,50 @@
FactoryBot.define do
factory :ci_reports_sbom_source, class: '::Gitlab::Ci::Reports::Sbom::Source' do
type { :dependency_scanning }
dependency_scanning
transient do
sequence(:input_file_path) { |n| "subproject-#{n}/package-lock.json" }
sequence(:source_file_path) { |n| "subproject-#{n}/package.json" }
trait :dependency_scanning do
type { :dependency_scanning }
transient do
sequence(:input_file_path) { |n| "subproject-#{n}/package-lock.json" }
sequence(:source_file_path) { |n| "subproject-#{n}/package.json" }
end
data do
{
'category' => 'development',
'input_file' => { 'path' => input_file_path },
'source_file' => { 'path' => source_file_path },
'package_manager' => { 'name' => 'npm' },
'language' => { 'name' => 'JavaScript' }
}
end
end
data do
{
'category' => 'development',
'input_file' => { 'path' => input_file_path },
'source_file' => { 'path' => source_file_path },
'package_manager' => { 'name' => 'npm' },
'language' => { 'name' => 'JavaScript' }
}
trait :container_scanning do
type { :container_scanning }
transient do
image_name { 'photon' }
sequence(:image_tag) { |n| "5.#{n}-12345678" }
operating_system_name { 'Photon OS' }
sequence(:operating_system_version) { |n| "5.#{n}" }
end
data do
{
'category' => 'development',
'image' => {
'name' => image_name,
'tag' => image_tag
},
'operating_system' => {
'name' => operating_system_name,
'version' => operating_system_version
}
}
end
end
skip_create

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe 'Projects > Settings > Webhook Settings', feature_category: :groups_and_projects do
RSpec.describe 'Projects > Settings > Webhook Settings', feature_category: :webhooks do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:webhooks_path) { project_hooks_path(project) }

View File

@ -1,9 +1,15 @@
import Reference from '~/content_editor/extensions/reference';
import ReferenceLabel from '~/content_editor/extensions/reference_label';
import AssetResolver from '~/content_editor/services/asset_resolver';
import {
RESOLVED_ISSUE_HTML,
RESOLVED_MERGE_REQUEST_HTML,
RESOLVED_EPIC_HTML,
RESOLVED_LABEL_HTML,
RESOLVED_SNIPPET_HTML,
RESOLVED_MILESTONE_HTML,
RESOLVED_USER_HTML,
RESOLVED_VULNERABILITY_HTML,
} from '../test_constants';
import {
createTestEditor,
@ -17,6 +23,7 @@ describe('content_editor/extensions/reference', () => {
let doc;
let p;
let reference;
let referenceLabel;
let renderMarkdown;
let assetResolver;
@ -25,33 +32,54 @@ describe('content_editor/extensions/reference', () => {
assetResolver = new AssetResolver({ renderMarkdown });
tiptapEditor = createTestEditor({
extensions: [Reference.configure({ assetResolver })],
extensions: [Reference.configure({ assetResolver }), ReferenceLabel],
});
({
builders: { doc, p, reference },
builders: { doc, p, reference, referenceLabel },
} = createDocBuilder({
tiptapEditor,
names: {
reference: { nodeType: Reference.name },
referenceLabel: { nodeType: ReferenceLabel.name },
},
}));
});
describe('when typing a valid reference input rule', () => {
const buildExpectedDoc = (href, originalText, referenceType, text) =>
const buildExpectedDoc = (href, originalText, referenceType, text = originalText) =>
doc(p(reference({ className: null, href, originalText, referenceType, text }), ' '));
const buildExpectedDocForLabel = (href, originalText, text, color) =>
doc(
p(
referenceLabel({
className: null,
referenceType: 'label',
href,
originalText,
text,
color,
}),
' ',
),
);
it.each`
inputRuleText | mockReferenceHtml | expectedDoc
${'#1 '} | ${RESOLVED_ISSUE_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab/-/issues/1', '#1', 'issue', '#1 (closed)')}
${'#1+ '} | ${RESOLVED_ISSUE_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab/-/issues/1', '#1+', 'issue', '500 error on MR approvers edit page (#1 - closed)')}
${'#1+s '} | ${RESOLVED_ISSUE_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab/-/issues/1', '#1+s', 'issue', '500 error on MR approvers edit page (#1 - closed) • Unassigned')}
${'!1 '} | ${RESOLVED_MERGE_REQUEST_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab/-/merge_requests/1', '!1', 'merge_request', '!1 (merged)')}
${'!1+ '} | ${RESOLVED_MERGE_REQUEST_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab/-/merge_requests/1', '!1+', 'merge_request', 'Enhance the LDAP group synchronization (!1 - merged)')}
${'!1+s '} | ${RESOLVED_MERGE_REQUEST_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab/-/merge_requests/1', '!1+s', 'merge_request', 'Enhance the LDAP group synchronization (!1 - merged) • John Doe')}
${'&1 '} | ${RESOLVED_EPIC_HTML} | ${() => buildExpectedDoc('/groups/gitlab-org/-/epics/1', '&1', 'epic', '&1')}
${'&1+ '} | ${RESOLVED_EPIC_HTML} | ${() => buildExpectedDoc('/groups/gitlab-org/-/epics/1', '&1+', 'epic', 'Approvals in merge request list (&1)')}
inputRuleText | mockReferenceHtml | expectedDoc
${'#1'} | ${RESOLVED_ISSUE_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab/-/issues/1', '#1', 'issue', '#1 (closed)')}
${'#1+'} | ${RESOLVED_ISSUE_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab/-/issues/1', '#1+', 'issue', '500 error on MR approvers edit page (#1 - closed)')}
${'#1+s'} | ${RESOLVED_ISSUE_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab/-/issues/1', '#1+s', 'issue', '500 error on MR approvers edit page (#1 - closed) • Unassigned')}
${'!1'} | ${RESOLVED_MERGE_REQUEST_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab/-/merge_requests/1', '!1', 'merge_request', '!1 (merged)')}
${'!1+'} | ${RESOLVED_MERGE_REQUEST_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab/-/merge_requests/1', '!1+', 'merge_request', 'Enhance the LDAP group synchronization (!1 - merged)')}
${'!1+s'} | ${RESOLVED_MERGE_REQUEST_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab/-/merge_requests/1', '!1+s', 'merge_request', 'Enhance the LDAP group synchronization (!1 - merged) • John Doe')}
${'&1'} | ${RESOLVED_EPIC_HTML} | ${() => buildExpectedDoc('/groups/gitlab-org/-/epics/1', '&1', 'epic', '&1')}
${'&1+'} | ${RESOLVED_EPIC_HTML} | ${() => buildExpectedDoc('/groups/gitlab-org/-/epics/1', '&1+', 'epic', 'Approvals in merge request list (&1)')}
${'@root'} | ${RESOLVED_USER_HTML} | ${() => buildExpectedDoc('/root', '@root', 'user')}
${'~Aquanix'} | ${RESOLVED_LABEL_HTML} | ${() => buildExpectedDocForLabel('/gitlab-org/gitlab-shell/-/issues?label_name=Aquanix', '~Aquanix', 'Aquanix', 'rgb(230, 84, 49)')}
${'%v4.0'} | ${RESOLVED_MILESTONE_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab-shell/-/milestones/5', '%v4.0', 'milestone')}
${'$25'} | ${RESOLVED_SNIPPET_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab-shell/-/snippets/25', '$25', 'snippet')}
${'[vulnerability:1]'} | ${RESOLVED_VULNERABILITY_HTML} | ${() => buildExpectedDoc('/gitlab-org/gitlab-shell/-/security/vulnerabilities/1', '[vulnerability:1]', 'vulnerability')}
`(
'replaces the input rule ($inputRuleText) with a reference node',
async ({ inputRuleText, mockReferenceHtml, expectedDoc }) => {
@ -61,8 +89,8 @@ describe('content_editor/extensions/reference', () => {
action() {
renderMarkdown.mockResolvedValueOnce(mockReferenceHtml);
tiptapEditor.commands.insertContent({ type: 'text', text: inputRuleText });
triggerNodeInputRule({ tiptapEditor, inputRuleText });
tiptapEditor.commands.insertContent({ type: 'text', text: `${inputRuleText} ` });
triggerNodeInputRule({ tiptapEditor, inputRuleText: `${inputRuleText} ` });
},
});

View File

@ -3,6 +3,11 @@ import {
RESOLVED_ISSUE_HTML,
RESOLVED_MERGE_REQUEST_HTML,
RESOLVED_EPIC_HTML,
RESOLVED_LABEL_HTML,
RESOLVED_SNIPPET_HTML,
RESOLVED_MILESTONE_HTML,
RESOLVED_USER_HTML,
RESOLVED_VULNERABILITY_HTML,
} from '../test_constants';
describe('content_editor/services/asset_resolver', () => {
@ -48,6 +53,32 @@ describe('content_editor/services/asset_resolver', () => {
text: '!1 (merged)',
};
const resolvedLabel = {
backgroundColor: 'rgb(230, 84, 49)',
href: '/gitlab-org/gitlab-shell/-/issues?label_name=Aquanix',
text: 'Aquanix',
};
const resolvedSnippet = {
href: '/gitlab-org/gitlab-shell/-/snippets/25',
text: '$25',
};
const resolvedMilestone = {
href: '/gitlab-org/gitlab-shell/-/milestones/5',
text: '%v4.0',
};
const resolvedUser = {
href: '/root',
text: '@root',
};
const resolvedVulnerability = {
href: '/gitlab-org/gitlab-shell/-/security/vulnerabilities/1',
text: '[vulnerability:1]',
};
describe.each`
referenceType | referenceId | sentMarkdown | returnedHtml | resolvedReference
${'issue'} | ${'#1'} | ${'#1 #1+ #1+s'} | ${RESOLVED_ISSUE_HTML} | ${resolvedIssue}
@ -59,7 +90,9 @@ describe('content_editor/services/asset_resolver', () => {
it(`resolves ${referenceType} reference to href, text, title and summary`, async () => {
renderMarkdown.mockResolvedValue(returnedHtml);
expect(await assetResolver.resolveReference(referenceId)).toEqual(resolvedReference);
expect(await assetResolver.resolveReference(referenceId)).toMatchObject(
resolvedReference,
);
});
it.each`
@ -74,6 +107,26 @@ describe('content_editor/services/asset_resolver', () => {
},
);
describe.each`
referenceType | referenceId | returnedHtml | resolvedReference
${'label'} | ${'~Aquanix'} | ${RESOLVED_LABEL_HTML} | ${resolvedLabel}
${'snippet'} | ${'$25'} | ${RESOLVED_SNIPPET_HTML} | ${resolvedSnippet}
${'milestone'} | ${'%v4.0'} | ${RESOLVED_MILESTONE_HTML} | ${resolvedMilestone}
${'user'} | ${'@root'} | ${RESOLVED_USER_HTML} | ${resolvedUser}
${'vulnerability'} | ${'[vulnerability:1]'} | ${RESOLVED_VULNERABILITY_HTML} | ${resolvedVulnerability}
`(
'for reference type $referenceType',
({ referenceType, referenceId, returnedHtml, resolvedReference }) => {
it(`resolves ${referenceType} reference to href, text and additional props (if any)`, async () => {
renderMarkdown.mockResolvedValue(returnedHtml);
expect(await assetResolver.resolveReference(referenceId)).toMatchObject(
resolvedReference,
);
});
},
);
it.each`
case | sentMarkdown | returnedHtml
${'no html is returned'} | ${''} | ${''}

View File

@ -44,3 +44,18 @@ export const RESOLVED_MERGE_REQUEST_HTML =
export const RESOLVED_EPIC_HTML =
'<p data-sourcepos="1:1-1:11" dir="auto"><a href="/groups/gitlab-org/-/epics/1" data-reference-type="epic" data-original="&amp;amp;1" data-link="false" data-link-reference="false" data-group="9970" data-epic="1" data-container="body" data-placement="top" title="Approvals in merge request list" class="gfm gfm-epic has-tooltip">&amp;1</a> <a href="/groups/gitlab-org/-/epics/1" data-reference-type="epic" data-original="&amp;amp;1+" data-link="false" data-link-reference="false" data-group="9970" data-epic="1" data-reference-format="+" data-container="body" data-placement="top" title="Approvals in merge request list" class="gfm gfm-epic has-tooltip">Approvals in merge request list (&amp;1)</a> <a href="/groups/gitlab-org/-/epics/1" data-reference-type="epic" data-original="&amp;amp;1+s" data-link="false" data-link-reference="false" data-group="9970" data-epic="1" data-reference-format="+s" data-container="body" data-placement="top" title="Approvals in merge request list" class="gfm gfm-epic has-tooltip">Approvals in merge request list (&amp;1)</a></p>';
export const RESOLVED_LABEL_HTML =
'<p data-sourcepos="1:1-1:29" dir="auto"><span class="gl-label gl-label-sm"><a href="/gitlab-org/gitlab-shell/-/issues?label_name=Aquanix" data-reference-type="label" data-original="~Aquanix" data-link="false" data-link-reference="false" data-project="2" data-label="5" data-container="body" data-placement="top" title="" class="gfm gfm-label has-tooltip gl-link gl-label-link"><span class="gl-label-text gl-label-text-light" data-container="body" data-html="true" style="background-color: #e65431">Aquanix</span></a></span> <span class="gl-label gl-label-sm"><a href="/gitlab-org/gitlab-shell/-/issues?label_name=Aquanix" data-reference-type="label" data-original="~Aquanix" data-link="false" data-link-reference="false" data-project="2" data-label="5" data-container="body" data-placement="top" title="" class="gfm gfm-label has-tooltip gl-link gl-label-link"><span class="gl-label-text gl-label-text-light" data-container="body" data-html="true" style="background-color: #e65431">Aquanix</span></a></span>+ <span class="gl-label gl-label-sm"><a href="/gitlab-org/gitlab-shell/-/issues?label_name=Aquanix" data-reference-type="label" data-original="~Aquanix" data-link="false" data-link-reference="false" data-project="2" data-label="5" data-container="body" data-placement="top" title="" class="gfm gfm-label has-tooltip gl-link gl-label-link"><span class="gl-label-text gl-label-text-light" data-container="body" data-html="true" style="background-color: #e65431">Aquanix</span></a></span>+s</p>';
export const RESOLVED_SNIPPET_HTML =
'<p data-sourcepos="1:1-1:14" dir="auto"><a href="/gitlab-org/gitlab-shell/-/snippets/25" data-reference-type="snippet" data-original="$25" data-link="false" data-link-reference="false" data-project="2" data-snippet="25" data-container="body" data-placement="top" title="test" class="gfm gfm-snippet has-tooltip">$25</a> <a href="/gitlab-org/gitlab-shell/-/snippets/25" data-reference-type="snippet" data-original="$25" data-link="false" data-link-reference="false" data-project="2" data-snippet="25" data-container="body" data-placement="top" title="test" class="gfm gfm-snippet has-tooltip">$25</a>+ <a href="/gitlab-org/gitlab-shell/-/snippets/25" data-reference-type="snippet" data-original="$25" data-link="false" data-link-reference="false" data-project="2" data-snippet="25" data-container="body" data-placement="top" title="test" class="gfm gfm-snippet has-tooltip">$25</a>+s</p>';
export const RESOLVED_MILESTONE_HTML =
'<p data-sourcepos="1:1-1:20" dir="auto"><a href="/gitlab-org/gitlab-shell/-/milestones/5" data-reference-type="milestone" data-original="%v4.0" data-link="false" data-link-reference="false" data-project="2" data-milestone="10" data-container="body" data-placement="top" title="" class="gfm gfm-milestone has-tooltip">%v4.0</a> <a href="/gitlab-org/gitlab-shell/-/milestones/5" data-reference-type="milestone" data-original="%v4.0" data-link="false" data-link-reference="false" data-project="2" data-milestone="10" data-container="body" data-placement="top" title="" class="gfm gfm-milestone has-tooltip">%v4.0</a>+ %v4.0+s</p>';
export const RESOLVED_USER_HTML =
'<p data-sourcepos="1:1-1:20" dir="auto"><a href="/root" data-reference-type="user" data-user="1" data-container="body" data-placement="top" class="gfm gfm-project_member js-user-link" title="Administrator">@root</a> <a href="/root" data-reference-type="user" data-user="1" data-container="body" data-placement="top" class="gfm gfm-project_member js-user-link" title="Administrator">@root</a>+ <a href="/root" data-reference-type="user" data-user="1" data-container="body" data-placement="top" class="gfm gfm-project_member js-user-link" title="Administrator">@root</a>+s</p>';
export const RESOLVED_VULNERABILITY_HTML =
'<p data-sourcepos="1:1-1:56" dir="auto"><a href="/gitlab-org/gitlab-shell/-/security/vulnerabilities/1" data-reference-type="vulnerability" data-original="[vulnerability:1]" data-link="false" data-link-reference="false" data-project="2" data-vulnerability="1" data-container="body" data-placement="top" title="oh no!" class="gfm gfm-vulnerability has-tooltip">[vulnerability:1]</a> <a href="/gitlab-org/gitlab-shell/-/security/vulnerabilities/1" data-reference-type="vulnerability" data-original="[vulnerability:1]" data-link="false" data-link-reference="false" data-project="2" data-vulnerability="1" data-container="body" data-placement="top" title="oh no!" class="gfm gfm-vulnerability has-tooltip">[vulnerability:1]</a>+ <a href="/gitlab-org/gitlab-shell/-/security/vulnerabilities/1" data-reference-type="vulnerability" data-original="[vulnerability:1]" data-link="false" data-link-reference="false" data-project="2" data-vulnerability="1" data-container="body" data-placement="top" title="oh no!" class="gfm gfm-vulnerability has-tooltip">[vulnerability:1]</a>+s</p>';

View File

@ -5,47 +5,93 @@ require 'fast_spec_helper'
RSpec.describe Gitlab::Ci::Reports::Sbom::Source, feature_category: :dependency_management do
let(:attributes) do
{
type: :dependency_scanning,
data: {
'category' => 'development',
'input_file' => { 'path' => 'package-lock.json' },
'source_file' => { 'path' => 'package.json' },
'package_manager' => { 'name' => 'npm' },
'language' => { 'name' => 'JavaScript' }
}
type: type,
data: { 'category' => 'development',
'package_manager' => { 'name' => 'npm' },
'language' => { 'name' => 'JavaScript' } }.merge(extra_attributes)
}
end
subject { described_class.new(**attributes) }
subject(:source) { described_class.new(**attributes) }
it 'has correct attributes' do
expect(subject).to have_attributes(
source_type: attributes[:type],
data: attributes[:data]
)
end
shared_examples_for 'it has correct common attributes' do
it 'has correct type and data' do
expect(subject).to have_attributes(
source_type: type,
data: attributes[:data]
)
end
describe '#source_file_path' do
it 'returns the correct source_file_path' do
expect(subject.source_file_path).to eq('package.json')
describe '#packager' do
it 'returns the correct package manager name' do
expect(subject.packager).to eq("npm")
end
end
describe '#language' do
it 'returns the correct language' do
expect(subject.language).to eq("JavaScript")
end
end
end
describe '#input_file_path' do
it 'returns the correct input_file_path' do
expect(subject.input_file_path).to eq("package-lock.json")
context 'when dependency scanning' do
let(:type) { :dependency_scanning }
let(:extra_attributes) do
{
'input_file' => { 'path' => 'package-lock.json' },
'source_file' => { 'path' => 'package.json' }
}
end
it_behaves_like 'it has correct common attributes'
describe '#source_file_path' do
it 'returns the correct source_file_path' do
expect(subject.source_file_path).to eq('package.json')
end
end
describe '#input_file_path' do
it 'returns the correct input_file_path' do
expect(subject.input_file_path).to eq("package-lock.json")
end
end
end
describe '#packager' do
it 'returns the correct package manager name' do
expect(subject.packager).to eq("npm")
context 'when container scanning' do
let(:type) { :container_scanning }
let(:extra_attributes) do
{
"image" => { "name" => "rhel", "tag" => "7.1" },
"operating_system" => { "name" => "Red Hat Enterprise Linux", "version" => "7" }
}
end
end
describe '#language' do
it 'returns the correct langauge' do
expect(subject.language).to eq("JavaScript")
it_behaves_like 'it has correct common attributes'
describe "#image_name" do
subject { source.image_name }
it { is_expected.to eq("rhel") }
end
describe "#image_tag" do
subject { source.image_tag }
it { is_expected.to eq("7.1") }
end
describe "#operating_system_name" do
subject { source.operating_system_name }
it { is_expected.to eq("Red Hat Enterprise Linux") }
end
describe "#operating_system_version" do
subject { source.operating_system_version }
it { is_expected.to eq("7") }
end
end
end

View File

@ -39,6 +39,15 @@ RSpec.describe Gitlab::Ci::Variables::Downstream::Generator, feature_category: :
]
end
let(:pipeline_dotenv_variables) do
[
{ key: 'PIPELINE_DOTENV_VAR1', value: 'variable 1' },
{ key: 'PIPELINE_DOTENV_VAR2', value: 'variable 2' },
{ key: 'PIPELINE_DOTENV_RAW_VAR3', value: '$REF1', raw: true },
{ key: 'PIPELINE_DOTENV_INTERPOLATION_VAR4', value: 'interpolate $REF1 $REF2' }
]
end
let(:bridge) do
instance_double(
'Ci::Bridge',
@ -48,7 +57,8 @@ RSpec.describe Gitlab::Ci::Variables::Downstream::Generator, feature_category: :
expand_file_refs?: false,
yaml_variables: yaml_variables,
pipeline_variables: pipeline_variables,
pipeline_schedule_variables: pipeline_schedule_variables
pipeline_schedule_variables: pipeline_schedule_variables,
dependency_variables: pipeline_dotenv_variables
)
end
@ -69,7 +79,12 @@ RSpec.describe Gitlab::Ci::Variables::Downstream::Generator, feature_category: :
{ key: 'PIPELINE_SCHEDULE_VAR1', value: 'variable 1' },
{ key: 'PIPELINE_SCHEDULE_VAR2', value: 'variable 2' },
{ key: 'PIPELINE_SCHEDULE_RAW_VAR3', value: '$REF1', raw: true },
{ key: 'PIPELINE_SCHEDULE_INTERPOLATION_VAR4', value: 'interpolate ref 1 ref 2' }
{ key: 'PIPELINE_SCHEDULE_INTERPOLATION_VAR4', value: 'interpolate ref 1 ref 2' },
{ key: 'PIPELINE_DOTENV_VAR1', value: 'variable 1' },
{ key: 'PIPELINE_DOTENV_VAR2', value: 'variable 2' },
{ key: 'PIPELINE_DOTENV_RAW_VAR3', value: '$REF1', raw: true },
{ key: 'PIPELINE_DOTENV_INTERPOLATION_VAR4', value: 'interpolate ref 1 ref 2' }
]
expect(generator.calculate).to contain_exactly(*expected)
@ -79,6 +94,7 @@ RSpec.describe Gitlab::Ci::Variables::Downstream::Generator, feature_category: :
allow(bridge).to receive(:yaml_variables).and_return([])
allow(bridge).to receive(:pipeline_variables).and_return([])
allow(bridge).to receive(:pipeline_schedule_variables).and_return([])
allow(bridge).to receive(:dependency_variables).and_return([])
expect(generator.calculate).to be_empty
end
@ -105,6 +121,10 @@ RSpec.describe Gitlab::Ci::Variables::Downstream::Generator, feature_category: :
[{ key: 'PIPELINE_SCHEDULE_INTERPOLATION_VAR', value: 'interpolate $REF1 $REF2 $FILE_REF3 $FILE_REF4' }]
end
let(:pipeline_dotenv_variables) do
[{ key: 'PIPELINE_DOTENV_INTERPOLATION_VAR', value: 'interpolate $REF1 $REF2 $FILE_REF3 $FILE_REF4' }]
end
context 'when expand_file_refs is true' do
before do
allow(bridge).to receive(:expand_file_refs?).and_return(true)
@ -114,7 +134,8 @@ RSpec.describe Gitlab::Ci::Variables::Downstream::Generator, feature_category: :
expected = [
{ key: 'INTERPOLATION_VAR', value: 'interpolate ref 1 ref 3 ' },
{ key: 'PIPELINE_INTERPOLATION_VAR', value: 'interpolate ref 1 ref 3 ' },
{ key: 'PIPELINE_SCHEDULE_INTERPOLATION_VAR', value: 'interpolate ref 1 ref 3 ' }
{ key: 'PIPELINE_SCHEDULE_INTERPOLATION_VAR', value: 'interpolate ref 1 ref 3 ' },
{ key: 'PIPELINE_DOTENV_INTERPOLATION_VAR', value: 'interpolate ref 1 ref 3 ' }
]
expect(generator.calculate).to contain_exactly(*expected)
@ -131,6 +152,7 @@ RSpec.describe Gitlab::Ci::Variables::Downstream::Generator, feature_category: :
{ key: 'INTERPOLATION_VAR', value: 'interpolate ref 1 $FILE_REF3 ' },
{ key: 'PIPELINE_INTERPOLATION_VAR', value: 'interpolate ref 1 $FILE_REF3 ' },
{ key: 'PIPELINE_SCHEDULE_INTERPOLATION_VAR', value: 'interpolate ref 1 $FILE_REF3 ' },
{ key: 'PIPELINE_DOTENV_INTERPOLATION_VAR', value: 'interpolate ref 1 $FILE_REF3 ' },
{ key: 'FILE_REF3', value: 'ref 3', variable_type: :file }
]

View File

@ -3,10 +3,13 @@
require "spec_helper"
RSpec.describe Gitlab::Git::Compare, feature_category: :source_code_management do
let_it_be(:repository) { create(:project, :repository).repository.raw }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:repository) { project.repository.raw }
let(:compare) { described_class.new(repository, SeedRepo::BigCommit::ID, SeedRepo::Commit::ID, straight: false) }
let(:compare_straight) { described_class.new(repository, SeedRepo::BigCommit::ID, SeedRepo::Commit::ID, straight: true) }
let(:compare) { described_class.new(repository, base, head, straight: false) }
let(:compare_straight) { described_class.new(repository, base, head, straight: true) }
let(:base) { SeedRepo::BigCommit::ID }
let(:head) { SeedRepo::Commit::ID }
describe '#commits' do
subject do
@ -109,4 +112,103 @@ RSpec.describe Gitlab::Git::Compare, feature_category: :source_code_management d
it { is_expected.to include('files/ruby/popen.rb') }
it { is_expected.not_to include('LICENSE') }
end
describe '#generated_files' do
subject(:generated_files) { compare.generated_files }
context 'with a detected generated file' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:repository) { project.repository.raw }
let_it_be(:branch) { 'generated-file-test' }
let_it_be(:base) do
project
.repository
.create_file(
project.creator,
'.gitattributes',
"*.txt gitlab-generated\n",
branch_name: branch,
message: 'Add .gitattributes file')
end
let_it_be(:head) do
project
.repository
.create_file(
project.creator,
'file1.rb',
"some content\n",
branch_name: branch,
message: 'Add file1')
project
.repository
.create_file(
project.creator,
'file1.txt',
"some content\n",
branch_name: branch,
message: 'Add file2')
end
it 'sets the diff as generated' do
expect(generated_files).to eq Set.new(['file1.txt'])
end
context 'when base is nil' do
let(:base) { nil }
it 'does not try to detect generated files' do
expect(repository).not_to receive(:detect_generated_files)
expect(repository).not_to receive(:find_changed_paths)
expect(generated_files).to eq Set.new
end
end
context 'when head is nil' do
let(:head) { nil }
it 'does not try to detect generated files' do
expect(repository).not_to receive(:detect_generated_files)
expect(repository).not_to receive(:find_changed_paths)
expect(generated_files).to eq Set.new
end
end
end
context 'with updated .gitattributes in the HEAD' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:repository) { project.repository.raw }
let_it_be(:branch) { 'generated-file-test' }
let_it_be(:head) do
project
.repository
.create_file(
project.creator,
'.gitattributes',
"*.txt gitlab-generated\n",
branch_name: branch,
message: 'Add .gitattributes file')
project
.repository
.create_file(
project.creator,
'file1.rb',
"some content\n",
branch_name: branch,
message: 'Add file1')
project
.repository
.create_file(
project.creator,
'file1.txt',
"some content\n",
branch_name: branch,
message: 'Add file2')
end
it 'does not set any files as generated' do
expect(generated_files).to eq Set.new
end
end
end
end

View File

@ -2812,4 +2812,69 @@ RSpec.describe Gitlab::Git::Repository, feature_category: :source_code_managemen
subject { repository.get_file_attributes(rev, paths, attrs) }
end
end
describe '#detect_generated_files' do
let(:project) do
create(:project, :custom_repo, files: {
'.gitattributes' => gitattr_content,
'file1.txt' => 'first file',
'file2.txt' => 'second file'
})
end
let(:repository) { project.repository.raw }
let(:rev) { 'master' }
let(:paths) { ['file1.txt', 'file2.txt'] }
subject(:generated_files) { repository.detect_generated_files(rev, paths) }
context 'when the linguist-generated attribute is used' do
let(:gitattr_content) { "*.txt text\nfile1.txt linguist-generated\n" }
it 'returns generated files only' do
expect(generated_files).to contain_exactly('file1.txt')
end
end
context 'when the gitlab-generated attribute is used' do
let(:gitattr_content) { "*.txt text\nfile1.txt gitlab-generated\n" }
it 'returns generated files only' do
expect(generated_files).to contain_exactly('file1.txt')
end
end
context 'when both linguist-generated and gitlab-generated attribute are used' do
let(:gitattr_content) { "*.txt text\nfile1.txt linguist-generated gitlab-generated\n" }
it 'returns generated files only' do
expect(generated_files).to contain_exactly('file1.txt')
end
end
context 'when the all files are generated' do
let(:gitattr_content) { "*.txt gitlab-generated\n" }
it 'returns all generated files' do
expect(generated_files).to eq paths.to_set
end
end
context 'when empty paths are given' do
let(:paths) { [] }
let(:gitattr_content) { "*.txt gitlab-generated\n" }
it 'returns an empty set' do
expect(generated_files).to eq Set.new
end
end
context 'when no generated overrides are used' do
let(:gitattr_content) { "*.txt text\n" }
it 'returns an empty set' do
expect(generated_files).to eq Set.new
end
end
end
end

View File

@ -518,6 +518,27 @@ RSpec.describe Ability do
end
describe '.allowed?' do
context "when used with 'read_namespace'" do
subject(:allowed?) { described_class.allowed?(nil, 'read_namespace') }
before do
allow(Gitlab::AppLogger).to receive(:info)
end
it 'logs the usage', :aggregate_failures do
allowed?
expect(Gitlab::AppLogger).to have_received(:info) do |args|
expect(args[:message]).to eq('Ability is in use')
expect(args[:ability]).to eq(:read_namespace)
expect(args[:caller_locations].first).to(
match(%r{spec/models/ability_spec.rb})
)
expect(args[:caller_locations].length).to eq(5)
end
end
end
context 'when used with :read_namespace' do
subject(:allowed?) { described_class.allowed?(nil, :read_namespace) }
@ -532,7 +553,7 @@ RSpec.describe Ability do
expect(args[:message]).to eq('Ability is in use')
expect(args[:ability]).to eq(:read_namespace)
expect(args[:caller_locations].first).to(
match(%r{/spec/models/ability_spec.rb:\d+:in `block \(4 levels\) in <top \(required\)>})
match(%r{spec/models/ability_spec.rb})
)
expect(args[:caller_locations].length).to eq(5)
end

View File

@ -3,9 +3,9 @@
require "spec_helper"
RSpec.describe Enums::Sbom, feature_category: :dependency_management do
describe '.purl_types' do
using RSpec::Parameterized::TableSyntax
using RSpec::Parameterized::TableSyntax
describe '.purl_types' do
subject(:actual_purl_type) { described_class.purl_types[package_manager] }
where(:given_package_manager, :expected_purl_type) do
@ -35,5 +35,63 @@ RSpec.describe Enums::Sbom, feature_category: :dependency_management do
expect(actual_purl_type).to eql(expected_purl_type)
end
end
it 'contains all of the dependency scanning and container scanning purl types' do
expect(described_class::DEPENDENCY_SCANNING_PURL_TYPES + described_class::CONTAINER_SCANNING_PURL_TYPES)
.to eql(described_class::PURL_TYPES.keys)
end
end
describe '.dependency_scanning_purl_type?' do
where(:purl_type, :expected) do
:composer | false
'composer' | true
'conan' | true
'gem' | true
'golang' | true
'maven' | true
'npm' | true
'nuget' | true
'pypi' | true
'unknown' | false
'apk' | false
'rpm' | false
'deb' | false
'wolfi' | false
end
with_them do
it 'returns true if the purl_type is for dependency_scanning' do
actual = described_class.dependency_scanning_purl_type?(purl_type)
expect(actual).to eql(expected)
end
end
end
describe '.container_scanning_purl_type?' do
where(:purl_type, :expected) do
'composer' | false
'conan' | false
'gem' | false
'golang' | false
'maven' | false
'npm' | false
'nuget' | false
'pypi' | false
'unknown' | false
:apk | false
'apk' | true
'rpm' | true
'deb' | true
'cbl-mariner' | true
'wolfi' | true
end
with_them do
it 'returns true if the purl_type is for container_scanning' do
actual = described_class.container_scanning_purl_type?(purl_type)
expect(actual).to eql(expected)
end
end
end
end

View File

@ -4052,59 +4052,4 @@ RSpec.describe Repository, feature_category: :source_code_management do
it { expect { file_attributes }.to raise_error(ArgumentError) }
end
end
describe '#filter_generated_files' do
let(:project) do
create(:project, :custom_repo, files: {
'.gitattributes' => gitattr_content,
'file1.txt' => 'first file',
'file2.txt' => 'second file'
})
end
let(:rev) { 'master' }
let(:paths) { ['file1.txt', 'file2.txt'] }
subject(:generated_files) { repository.filter_generated_files(rev, paths) }
context 'when the linguist-generated attribute is used' do
let(:gitattr_content) { "*.txt text\nfile1.txt linguist-generated\n" }
it 'returns generated files only' do
expect(generated_files).to contain_exactly('file2.txt')
end
end
context 'when the gitlab-generated attribute is used' do
let(:gitattr_content) { "*.txt text\nfile1.txt gitlab-generated\n" }
it 'returns generated files only' do
expect(generated_files).to contain_exactly('file2.txt')
end
end
context 'when both linguist-generated and gitlab-generated attribute are used' do
let(:gitattr_content) { "*.txt text\nfile1.txt linguist-generated gitlab-generated\n" }
it 'returns generated files only' do
expect(generated_files).to contain_exactly('file2.txt')
end
end
context 'when no generated overrides are used' do
let(:gitattr_content) { "*.txt text\n" }
it 'returns the original paths' do
expect(generated_files).to eq paths
end
end
context 'when the given files are generated' do
let(:gitattr_content) { "*.txt gitlab-generated\n" }
it 'returns an empty array' do
expect(generated_files).to eq []
end
end
end
end

View File

@ -134,7 +134,7 @@ RSpec.describe RuboCop::Cop::BackgroundMigration::DictionaryFile, feature_catego
end
context 'with dictionary file' do
let(:introduced_by_url) { 'https://test_url' }
let(:introduced_by_url) { 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132639' }
let(:finalize_after) { '20230507160251' }
before do
@ -158,6 +158,25 @@ RSpec.describe RuboCop::Cop::BackgroundMigration::DictionaryFile, feature_catego
end
end
context 'when the `introduced_by_url` is not correct' do
let(:introduced_by_url) { 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132639/invalid' }
it 'throws offense on having a correct url' do
expect_offense(<<~RUBY)
class QueueMyMigration < Gitlab::Database::Migration[2.1]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{format('Invalid `introduced_by_url` url for the dictionary. Please use the following format: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/XXX')}
def up
queue_batched_background_migration(
'MyMigration',
:users,
:id
)
end
end
RUBY
end
end
context 'with required dictionary keys' do
it 'does not throw offense with appropriate dictionary file' do
expect_no_offenses(<<~RUBY)

View File

@ -25,4 +25,41 @@ RSpec.describe ::Ml::CreateModelVersionService, feature_category: :mlops do
expect(model.reload.latest_version.version).to eq('4.0.0')
end
end
context 'when a version is created' do
it 'creates a package' do
expect { service }.to change { Ml::ModelVersion.count }.by(1).and change {
Packages::MlModel::Package.count
}.by(1)
expect(model.reload.latest_version.package.name).to eq(model.name)
expect(model.latest_version.package.version).to eq(model.latest_version.version)
end
end
context 'when a version is created and the package already exists' do
it 'does not creates a package' do
next_version = Ml::IncrementVersionService.new(model.latest_version.try(:version)).execute
create(:ml_model_package, name: model.name, version: next_version, project: model.project)
expect { service }.to change { Ml::ModelVersion.count }.by(1).and not_change {
Packages::MlModel::Package.count
}
expect(model.reload.latest_version.package.name).to eq(model.name)
expect(model.latest_version.package.version).to eq(model.latest_version.version)
end
end
context 'when a version is created and an existing package supplied' do
it 'does not creates a package' do
next_version = Ml::IncrementVersionService.new(model.latest_version.try(:version)).execute
package = create(:ml_model_package, name: model.name, version: next_version, project: model.project)
service = described_class.new(model, { package: package })
expect { service.execute }.to change { Ml::ModelVersion.count }.by(1).and not_change {
Packages::MlModel::Package.count
}
expect(model.reload.latest_version.package.name).to eq(model.name)
expect(model.latest_version.package.version).to eq(model.latest_version.version)
end
end
end