Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
c3ddbeb162
commit
07cbb41fee
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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>"] }
|
||||
}
|
||||
]
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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. |
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||

|
||||
|
||||
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 |
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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/)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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} ` });
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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'} | ${''} | ${''}
|
||||
|
|
|
|||
|
|
@ -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;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">&1</a> <a href="/groups/gitlab-org/-/epics/1" data-reference-type="epic" data-original="&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 (&1)</a> <a href="/groups/gitlab-org/-/epics/1" data-reference-type="epic" data-original="&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 (&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>';
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue