Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
48e30ea32f
commit
2c87a975e3
62 changed files with 1423 additions and 97 deletions
|
@ -99,7 +99,7 @@ rules:
|
|||
message: 'Migrate to GlSkeletonLoader, or import GlDeprecatedSkeletonLoading.'
|
||||
overrides:
|
||||
- files:
|
||||
- '{,ee/,jh/}spec/frontend*/**/*'
|
||||
- '{,ee/,jh/}spec/frontend*/**/*'
|
||||
rules:
|
||||
'@gitlab/require-i18n-strings': off
|
||||
'@gitlab/no-runtime-template-compiler': off
|
||||
|
@ -139,11 +139,13 @@ overrides:
|
|||
parser: '@graphql-eslint/eslint-plugin'
|
||||
operations:
|
||||
- '{,ee/,jh/}app/**/*.graphql'
|
||||
# You can run `bundle exec rake gitlab:graphql:schema:dump` and then uncomment this line
|
||||
# schema: './tmp/tests/graphql/gitlab_schema.graphql'
|
||||
# You can run `bundle exec rake gitlab:graphql:schema:dump` and then uncomment this line
|
||||
# schema: './tmp/tests/graphql/gitlab_schema.graphql'
|
||||
rules:
|
||||
filenames/match-regex: off
|
||||
spaced-comment: off
|
||||
# TODO: We need a way to include this rule + support ee_else_ce fragments
|
||||
#'@graphql-eslint/unique-fragment-name': error
|
||||
# TODO: Uncomment these rules when then `schema` is available
|
||||
#'@graphql-eslint/fragments-on-composite-type': error
|
||||
#'@graphql-eslint/known-argument-names': error
|
||||
|
@ -151,4 +153,3 @@ overrides:
|
|||
'@graphql-eslint/no-anonymous-operations': error
|
||||
'@graphql-eslint/unique-operation-name': error
|
||||
'@graphql-eslint/require-id-when-available': error
|
||||
'@graphql-eslint/unique-fragment-name': error
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
/milestone %
|
||||
/assign `@EM/PM` (choose the DRI; remove backticks here, and below)
|
||||
|
||||
**Be sure to link this MR to the relevant issue(s).**
|
||||
**Be sure to link this MR to the relevant issues.**
|
||||
|
||||
- Deprecation issue:
|
||||
- Removal issue:
|
||||
- MR that removes the feature (optional):
|
||||
- MR that removed (or _will_ remove) the feature:
|
||||
|
||||
If there is no relevant deprecation issue, hit pause and:
|
||||
|
||||
|
@ -45,6 +45,7 @@ Please review the [guidelines for removals](https://about.gitlab.com/handbook/ma
|
|||
- [ ] Follow the process to [create a removal YAML file](https://about.gitlab.com/handbook/marketing/blog/release-posts/#creating-a-removal-entry).
|
||||
- [ ] Add reviewers by the 10th.
|
||||
- [ ] When ready to be merged and not later than the 15th, add the ~ready label and @ message the TW for final review and merge.
|
||||
- Removal notices should not be merged before the code is removed from the product. Do not mark ~ready until the removal is complete, or you are certain it will be completed within the current milestone and released. If PMs are not sure, they should confirm with their Engineering Manager.
|
||||
|
||||
## Reviewers
|
||||
|
||||
|
@ -66,6 +67,8 @@ with the same process as regular docs MRs. Add suggestions as needed, @ message
|
|||
the PM to inform them the first review is complete, and remove
|
||||
yourself as a reviewer if it's not yet ready for merge.
|
||||
|
||||
**Removal notices should not be merged before the code is removed from the product.**
|
||||
|
||||
<details>
|
||||
<summary>Expand for Details</summary>
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
53768dae0bc6395d2b80438286723a912aa50921
|
||||
1b1b95408d11a2532db5a44ffefd5cbab6e0effd
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# This fragment is used as ee-else-ce
|
||||
# eslint-disable-next-line @graphql-eslint/unique-fragment-name
|
||||
fragment HttpIntegrationPayloadData on AlertManagementHttpIntegration {
|
||||
id
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# This fragment is used as ee-else-ce
|
||||
# eslint-disable-next-line @graphql-eslint/unique-fragment-name
|
||||
fragment BoardFragment on Board {
|
||||
id
|
||||
name
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#import "./board_list_shared.fragment.graphql"
|
||||
|
||||
# This fragment is used as ee-else-ce
|
||||
# eslint-disable-next-line @graphql-eslint/unique-fragment-name
|
||||
fragment BoardListFragment on BoardList {
|
||||
...BoardListShared
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# This fragment is used as ee-else-ce
|
||||
# eslint-disable-next-line @graphql-eslint/unique-fragment-name
|
||||
fragment BoardScopeFragment on Board {
|
||||
id
|
||||
name
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#import "~/graphql_shared/fragments/issue.fragment.graphql"
|
||||
|
||||
# This fragment is used as ee-else-ce
|
||||
# eslint-disable-next-line @graphql-eslint/unique-fragment-name
|
||||
fragment Issue on Issue {
|
||||
id
|
||||
...IssueNode
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
fragment IterationShared on Iteration {
|
||||
fragment Iteration on Iteration {
|
||||
id
|
||||
title
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
fragment PageInfo on PageInfo {
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
# This fragment is used as ee-else-ce
|
||||
# eslint-disable-next-line @graphql-eslint/require-id-when-available, @graphql-eslint/unique-fragment-name
|
||||
# eslint-disable-next-line @graphql-eslint/require-id-when-available
|
||||
fragment IncidentFields on Issue {
|
||||
severity
|
||||
escalationStatus
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
fragment Label on Label {
|
||||
id
|
||||
color
|
||||
textColor
|
||||
title
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
#import "~/graphql_shared/fragments/label.fragment.graphql"
|
||||
#import "./label.fragment.graphql"
|
||||
|
||||
query searchLabels($fullPath: ID!, $search: String, $isProject: Boolean = false) {
|
||||
group(fullPath: $fullPath) @skip(if: $isProject) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#import "~/graphql_shared/fragments/user.fragment.graphql"
|
||||
#import "./user.fragment.graphql"
|
||||
|
||||
query searchUsers($fullPath: ID!, $search: String, $isProject: Boolean = false) {
|
||||
group(fullPath: $fullPath) @skip(if: $isProject) {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
fragment User on User {
|
||||
id
|
||||
avatarUrl
|
||||
name
|
||||
username
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
# This fragment is used as ee-else-ce
|
||||
# eslint-disable-next-line @graphql-eslint/unique-fragment-name
|
||||
fragment TreeEntryCommit on LogTreeCommit {
|
||||
sha
|
||||
message
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# This fragment is used as ee-else-ce
|
||||
# eslint-disable-next-line @graphql-eslint/unique-fragment-name
|
||||
fragment ProjectPathLocksFragment on Project {
|
||||
id
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#import "./runner_details_shared.fragment.graphql"
|
||||
|
||||
# This fragment is used as ee-else-ce
|
||||
# eslint-disable-next-line @graphql-eslint/unique-fragment-name
|
||||
fragment RunnerDetails on CiRunner {
|
||||
...RunnerDetailsShared
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ query groupMilestones($fullPath: ID!, $title: String, $state: MilestoneStateEnum
|
|||
includeAncestors: true
|
||||
) {
|
||||
nodes {
|
||||
...SidebarMilestoneFragment
|
||||
...MilestoneFragment
|
||||
state
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ query mergeRequestMilestone($fullPath: ID!, $iid: String!) {
|
|||
__typename
|
||||
id
|
||||
attribute: milestone {
|
||||
...SidebarMilestoneFragment
|
||||
...MilestoneFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
fragment SidebarMilestoneFragment on Milestone {
|
||||
fragment MilestoneFragment on Milestone {
|
||||
id
|
||||
title
|
||||
webUrl: webPath
|
||||
|
|
|
@ -8,7 +8,7 @@ query projectIssueMilestone($fullPath: ID!, $iid: String!) {
|
|||
__typename
|
||||
id
|
||||
attribute: milestone {
|
||||
...SidebarMilestoneFragment
|
||||
...MilestoneFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ query projectMilestones($fullPath: ID!, $title: String, $state: MilestoneStateEn
|
|||
includeAncestors: true
|
||||
) {
|
||||
nodes {
|
||||
...SidebarMilestoneFragment
|
||||
...MilestoneFragment
|
||||
state
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,8 @@ class Admin::TopicsController < Admin::ApplicationController
|
|||
[
|
||||
:avatar,
|
||||
:description,
|
||||
:name
|
||||
:name,
|
||||
:title
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
fragment LocalPageInfo on PageInfo {
|
||||
fragment PageInfo on PageInfo {
|
||||
__typename
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
|
@ -6,7 +6,7 @@ fragment LocalPageInfo on PageInfo {
|
|||
endCursor
|
||||
}
|
||||
|
||||
fragment LocalTreeEntry on Entry {
|
||||
fragment TreeEntry on Entry {
|
||||
__typename
|
||||
id
|
||||
sha
|
||||
|
@ -34,12 +34,12 @@ query getFiles(
|
|||
edges {
|
||||
__typename
|
||||
node {
|
||||
...LocalTreeEntry
|
||||
...TreeEntry
|
||||
webPath
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
...LocalPageInfo
|
||||
...PageInfo
|
||||
}
|
||||
}
|
||||
submodules(first: $pageSize, after: $nextPageCursor) {
|
||||
|
@ -47,13 +47,13 @@ query getFiles(
|
|||
edges {
|
||||
__typename
|
||||
node {
|
||||
...LocalTreeEntry
|
||||
...TreeEntry
|
||||
webUrl
|
||||
treeUrl
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
...LocalPageInfo
|
||||
...PageInfo
|
||||
}
|
||||
}
|
||||
blobs(first: $pageSize, after: $nextPageCursor) {
|
||||
|
@ -61,14 +61,14 @@ query getFiles(
|
|||
edges {
|
||||
__typename
|
||||
node {
|
||||
...LocalTreeEntry
|
||||
...TreeEntry
|
||||
mode
|
||||
webPath
|
||||
lfsOid
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
...LocalPageInfo
|
||||
...PageInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2903,7 +2903,7 @@ class Project < ApplicationRecord
|
|||
if @topic_list != self.topic_list
|
||||
self.topics.delete_all
|
||||
self.topics = @topic_list.map do |topic|
|
||||
Projects::Topic.where('lower(name) = ?', topic.downcase).order(total_projects_count: :desc).first_or_create(name: topic)
|
||||
Projects::Topic.where('lower(name) = ?', topic.downcase).order(total_projects_count: :desc).first_or_create(name: topic, title: topic)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ module Projects
|
|||
|
||||
validates :name, presence: true, length: { maximum: 255 }
|
||||
validates :name, uniqueness: { case_sensitive: false }, if: :name_changed?
|
||||
validates :title, presence: true, length: { maximum: 255 }, on: :create
|
||||
validates :description, length: { maximum: 1024 }
|
||||
|
||||
has_many :project_topics, class_name: 'Projects::ProjectTopic'
|
||||
|
|
|
@ -3,12 +3,19 @@
|
|||
|
||||
.form-group
|
||||
= f.label :name do
|
||||
= _("Topic name")
|
||||
= f.text_field :name, placeholder: _('My topic'), class: 'form-control input-lg', data: { qa_selector: 'topic_name_field' },
|
||||
= _("Topic slug (name)")
|
||||
= f.text_field :name, placeholder: _('my-topic'), class: 'form-control input-lg', data: { qa_selector: 'topic_name_field' },
|
||||
required: true,
|
||||
title: _('Please fill in a name for your topic.'),
|
||||
autofocus: true
|
||||
|
||||
.form-group
|
||||
= f.label :title do
|
||||
= _("Topic title")
|
||||
= f.text_field :title, placeholder: _('My topic'), class: 'form-control input-lg', data: { qa_selector: 'topic_title_field' },
|
||||
required: true,
|
||||
title: _('Please fill in a title for your topic.')
|
||||
|
||||
.form-group
|
||||
= f.label :description, _("Description")
|
||||
= render layout: 'shared/md_preview', locals: { url: preview_markdown_admin_topics_path, referenced_users: false } do
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
- topic = local_assigns.fetch(:topic)
|
||||
- title = topic.title || topic.name
|
||||
|
||||
%li.topic-row.gl-py-3.gl-align-items-center{ class: 'gl-display-flex!', data: { qa_selector: 'topic_row_content' } }
|
||||
.avatar-container.rect-avatar.s40.gl-flex-shrink-0
|
||||
|
@ -6,7 +7,9 @@
|
|||
|
||||
.gl-min-w-0.gl-flex-grow-1
|
||||
.title
|
||||
= link_to topic.name, topic_explore_projects_path(topic_name: topic.name)
|
||||
= link_to title, topic_explore_projects_path(topic_name: topic.name)
|
||||
%div
|
||||
= topic.name
|
||||
|
||||
.stats.gl-text-gray-500.gl-flex-shrink-0.gl-display-none.gl-sm-display-flex
|
||||
%span.gl-ml-5.has-tooltip{ title: n_('%d project', '%d projects', topic.total_projects_count) % topic.total_projects_count }
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
breaking_change: true
|
||||
reporter: NicoleSchwartz
|
||||
body: |
|
||||
In GitLab 15.0, for Dependency Scanning, the default version of Java will be updated to 17. This is the same as [the most up-to-date Long Term Support (LTS) version](https://en.wikipedia.org/wiki/Java_version_history). GitLab still [supports the same versions as it does today (8, 11, 13, 14, 15, 16, 17)](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#configuring-specific-analyzers-used-by-dependency-scanning). Only the enabled default is changing. To change the default, set the `DS_Java_Version` variable.
|
||||
In GitLab 15.0, for Dependency Scanning, the default version of Java that the scanner expects will be updated from 11 to 17. Java 17 is [the most up-to-date Long Term Support (LTS) version](https://en.wikipedia.org/wiki/Java_version_history). Dependency scanning continues to support the same [range of versions (8, 11, 13, 14, 15, 16, 17)](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#supported-languages-and-package-managers), only the default version is changing. If your project uses the previous default of Java 11, be sure to [set the `DS_Java_Version` variable to match](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#configuring-specific-analyzers-used-by-dependency-scanning).
|
||||
# The following items are not published on the docs page, but may be used in the future.
|
||||
stage: secure # (optional - may be required in the future) String value of the stage that the feature was created in. e.g., Growth
|
||||
tiers: ultimate # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
|
||||
|
|
9
db/docs/group_features.yml
Normal file
9
db/docs/group_features.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
table_name: group_features
|
||||
classes:
|
||||
- Groups::FeatureSetting
|
||||
feature_categories:
|
||||
- subgroups
|
||||
description: TODO
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82017
|
||||
milestone: '14.10'
|
9
db/docs/project_build_artifacts_size_refreshes.yml
Normal file
9
db/docs/project_build_artifacts_size_refreshes.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
table_name: project_build_artifacts_size_refreshes
|
||||
classes:
|
||||
- Projects::BuildArtifactsSizeRefresh
|
||||
feature_categories:
|
||||
- build_artifacts
|
||||
description: TODO
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81306
|
||||
milestone: '14.9'
|
9
db/docs/protected_environment_approval_rules.yml
Normal file
9
db/docs/protected_environment_approval_rules.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
table_name: protected_environment_approval_rules
|
||||
classes:
|
||||
- ProtectedEnvironments::ApprovalRule
|
||||
feature_categories:
|
||||
- continuous_delivery
|
||||
description: TODO
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82800
|
||||
milestone: '14.10'
|
10
db/migrate/20220331125725_add_title_to_topic.rb
Normal file
10
db/migrate/20220331125725_add_title_to_topic.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddTitleToTopic < Gitlab::Database::Migration[1.0]
|
||||
# rubocop:disable Migration/AddLimitToTextColumns
|
||||
# limit is added in 20220331130726_add_text_limit_to_topics_title.rb
|
||||
def change
|
||||
add_column :topics, :title, :text
|
||||
end
|
||||
# rubocop:enable Migration/AddLimitToTextColumns
|
||||
end
|
13
db/migrate/20220331130726_add_text_limit_to_topics_title.rb
Normal file
13
db/migrate/20220331130726_add_text_limit_to_topics_title.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddTextLimitToTopicsTitle < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_text_limit :topics, :title, 255
|
||||
end
|
||||
|
||||
def down
|
||||
remove_text_limit :topics, :title
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ScheduleBackfillTopicsTitle < Gitlab::Database::Migration[1.0]
|
||||
MIGRATION = 'BackfillTopicsTitle'
|
||||
DELAY_INTERVAL = 2.minutes
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
queue_background_migration_jobs_by_range_at_intervals(
|
||||
define_batchable_model('topics'),
|
||||
MIGRATION,
|
||||
DELAY_INTERVAL,
|
||||
track_jobs: true
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
end
|
1
db/schema_migrations/20220331125725
Normal file
1
db/schema_migrations/20220331125725
Normal file
|
@ -0,0 +1 @@
|
|||
a7e5490e9b53cbbed01c03690cbe0bb4668adb17ec4fe14ca96e021f2e313b38
|
1
db/schema_migrations/20220331130726
Normal file
1
db/schema_migrations/20220331130726
Normal file
|
@ -0,0 +1 @@
|
|||
bcaf6139100dc5658d33292e8e5484d1d6278f022eeb6e3bcd519efdccdf4470
|
1
db/schema_migrations/20220331133802
Normal file
1
db/schema_migrations/20220331133802
Normal file
|
@ -0,0 +1 @@
|
|||
0e96430b245f6f04447ee50b6e0c0b9d7828cfeaf1f08e303aa04bb40a117a7f
|
|
@ -21050,6 +21050,8 @@ CREATE TABLE topics (
|
|||
description text,
|
||||
total_projects_count bigint DEFAULT 0 NOT NULL,
|
||||
non_private_projects_count bigint DEFAULT 0 NOT NULL,
|
||||
title text,
|
||||
CONSTRAINT check_223b50f9be CHECK ((char_length(title) <= 255)),
|
||||
CONSTRAINT check_26753fb43a CHECK ((char_length(avatar) <= 255)),
|
||||
CONSTRAINT check_5d1a07c8c8 CHECK ((char_length(description) <= 1024)),
|
||||
CONSTRAINT check_7a90d4c757 CHECK ((char_length(name) <= 255))
|
||||
|
|
|
@ -1422,7 +1422,7 @@ Supported attributes:
|
|||
| `emails_disabled` | boolean | **{dotted-circle}** No | Disable email notifications. |
|
||||
| `external_authorization_classification_label` **(PREMIUM)** | string | **{dotted-circle}** No | The classification label for the project. |
|
||||
| `forking_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
|
||||
| `import_url` | string | **{dotted-circle}** No | URL to import repository from. |
|
||||
| `import_url` | string | **{dotted-circle}** No | URL the repository was imported from. |
|
||||
| `issues_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
|
||||
| `issues_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable issues for this project. Use `issues_access_level` instead. |
|
||||
| `issues_template` **(PREMIUM)** | string | **{dotted-circle}** No | Default description for Issues. Description is parsed with GitLab Flavored Markdown. See [Templates for issues and merge requests](#templates-for-issues-and-merge-requests). |
|
||||
|
|
|
@ -38,21 +38,24 @@ Example response:
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "GitLab",
|
||||
"name": "gitlab",
|
||||
"title": "GitLab",
|
||||
"description": "GitLab is an open source end-to-end software development platform with built-in version control, issue tracking, code review, CI/CD, and more.",
|
||||
"total_projects_count": 1000,
|
||||
"avatar_url": "http://www.gravatar.com/avatar/a0d477b3ea21970ce6ffcbb817b0b435?s=80&d=identicon"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Git",
|
||||
"name": "git",
|
||||
"title": "Git",
|
||||
"description": "Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.",
|
||||
"total_projects_count": 900,
|
||||
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Git LFS",
|
||||
"name": "git-lfs",
|
||||
"title": "Git LFS",
|
||||
"description": null,
|
||||
"total_projects_count": 300,
|
||||
"avatar_url": null
|
||||
|
@ -85,7 +88,8 @@ Example response:
|
|||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"name": "GitLab",
|
||||
"name": "gitlab",
|
||||
"title": "GitLab",
|
||||
"description": "GitLab is an open source end-to-end software development platform with built-in version control, issue tracking, code review, CI/CD, and more.",
|
||||
"total_projects_count": 1000,
|
||||
"avatar_url": "http://www.gravatar.com/avatar/a0d477b3ea21970ce6ffcbb817b0b435?s=80&d=identicon"
|
||||
|
@ -112,7 +116,8 @@ Supported attributes:
|
|||
|
||||
| Attribute | Type | Required | Description |
|
||||
| ------------- | ------- | ---------------------- | ----------- |
|
||||
| `name` | string | **{check-circle}** Yes | Name |
|
||||
| `name` | string | **{check-circle}** Yes | Slug (name) |
|
||||
| `title` | string | **{check-circle}** Yes | Title |
|
||||
| `avatar` | file | **{dotted-circle}** No | Avatar |
|
||||
| `description` | string | **{dotted-circle}** No | Description |
|
||||
|
||||
|
@ -120,7 +125,7 @@ Example request:
|
|||
|
||||
```shell
|
||||
curl --request POST \
|
||||
--data "name=topic1" \
|
||||
--data "name=topic1&title=Topic 1" \
|
||||
--header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
"https://gitlab.example.com/api/v4/topics"
|
||||
```
|
||||
|
@ -131,6 +136,7 @@ Example response:
|
|||
{
|
||||
"id": 1,
|
||||
"name": "topic1",
|
||||
"title": "Topic 1",
|
||||
"description": null,
|
||||
"total_projects_count": 0,
|
||||
"avatar_url": null
|
||||
|
@ -152,7 +158,8 @@ Supported attributes:
|
|||
| `id` | integer | **{check-circle}** Yes | ID of project topic |
|
||||
| `avatar` | file | **{dotted-circle}** No | Avatar |
|
||||
| `description` | string | **{dotted-circle}** No | Description |
|
||||
| `name` | string | **{dotted-circle}** No | Name |
|
||||
| `name` | string | **{dotted-circle}** No | Slug (name) |
|
||||
| `title` | string | **{dotted-circle}** No | Title |
|
||||
|
||||
Example request:
|
||||
|
||||
|
@ -169,6 +176,7 @@ Example response:
|
|||
{
|
||||
"id": 1,
|
||||
"name": "topic1",
|
||||
"title": "Topic 1",
|
||||
"description": null,
|
||||
"total_projects_count": 0,
|
||||
"avatar_url": null
|
||||
|
|
|
@ -45,7 +45,7 @@ You can combine entries if they happened in the same release:
|
|||
|
||||
## Use a note to describe the state of the feature flag
|
||||
|
||||
Information about feature flags should be in a **Note** at the start of the topic (just below the version history).
|
||||
Information about feature flags should be in a `FLAG` note at the start of the topic (just below the version history).
|
||||
|
||||
The note has three parts, and follows this structure:
|
||||
|
||||
|
@ -62,6 +62,7 @@ FLAG:
|
|||
|--------------------------|---------------|
|
||||
| Available | `On self-managed GitLab, by default this feature is available. To hide the feature, ask an administrator to [disable the feature flag](<path to>/administration/feature_flags.md) named <flag name>.` |
|
||||
| Unavailable | `On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](<path to>/administration/feature_flags.md) named <flag name>.` |
|
||||
| Available to some users | `On self-managed GitLab, by default this feature is available to a subset of users. To show or hide the feature for all, ask an administrator to [change the status of the feature flag](<path to>/administration/feature_flags.md) named <flag name>.` |
|
||||
| Available, per-group | `On self-managed GitLab, by default this feature is available. To hide the feature per group, ask an administrator to [disable the feature flag](<path to>/administration/feature_flags.md) named <flag name>.` |
|
||||
| Unavailable, per-group | `On self-managed GitLab, by default this feature is not available. To make it available per group, ask an administrator to [enable the feature flag](<path to>/administration/feature_flags.md) named <flag name>.` |
|
||||
| Available, per-project | `On self-managed GitLab, by default this feature is available. To hide the feature per project or for your entire instance, ask an administrator to [disable the feature flag](<path to>/administration/feature_flags.md) named <flag name>.` |
|
||||
|
|
|
@ -52,7 +52,7 @@ as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#brea
|
|||
Before updating GitLab, review the details carefully to determine if you need to make any
|
||||
changes to your code, settings, or workflow.
|
||||
|
||||
In GitLab 15.0, for Dependency Scanning, the default version of Java will be updated to 17. This is the same as [the most up-to-date Long Term Support (LTS) version](https://en.wikipedia.org/wiki/Java_version_history). GitLab still [supports the same versions as it does today (8, 11, 13, 14, 15, 16, 17)](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#configuring-specific-analyzers-used-by-dependency-scanning). Only the enabled default is changing. To change the default, set the `DS_Java_Version` variable.
|
||||
In GitLab 15.0, for Dependency Scanning, the default version of Java that the scanner expects will be updated from 11 to 17. Java 17 is [the most up-to-date Long Term Support (LTS) version](https://en.wikipedia.org/wiki/Java_version_history). Dependency scanning continues to support the same [range of versions (8, 11, 13, 14, 15, 16, 17)](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#supported-languages-and-package-managers), only the default version is changing. If your project uses the previous default of Java 11, be sure to [set the `DS_Java_Version` variable to match](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#configuring-specific-analyzers-used-by-dependency-scanning).
|
||||
|
||||
**Planned removal milestone: 15.0 (2021-05-22)**
|
||||
|
||||
|
|
|
@ -107,13 +107,9 @@ workflows.
|
|||
|
||||
## The GitLab Terraform provider
|
||||
|
||||
NOTE:
|
||||
The GitLab Terraform provider is released separately from GitLab.
|
||||
We are working on migrating the GitLab Terraform provider to GitLab.com.
|
||||
|
||||
The [GitLab Terraform provider](https://github.com/gitlabhq/terraform-provider-gitlab) is a plugin for Terraform to facilitate
|
||||
managing of GitLab resources such as users, groups, and projects.
|
||||
Its documentation is available on [Terraform](https://registry.terraform.io/providers/gitlabhq/gitlab/latest/docs).
|
||||
The [GitLab Terraform provider](https://github.com/gitlabhq/terraform-provider-gitlab) is a Terraform plugin to facilitate
|
||||
managing of GitLab resources such as users, groups, and projects. It is released separately from GitLab
|
||||
and its documentation is available on [Terraform](https://registry.terraform.io/providers/gitlabhq/gitlab/latest/docs).
|
||||
|
||||
## Create a new cluster through IaC
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ Prerequisites:
|
|||
To export a project and its data, follow these steps:
|
||||
|
||||
1. On the top bar, select **Menu > Projects** and find your project.
|
||||
1. On the left sidebar, select **Settings**.
|
||||
1. On the left sidebar, select **Settings > General**.
|
||||
1. Expand **Advanced**.
|
||||
1. Select **Export project**.
|
||||
1. After the export is generated, you should receive an email with a link to download the file.
|
||||
|
|
|
@ -6,6 +6,7 @@ module API
|
|||
class Topic < Grape::Entity
|
||||
expose :id
|
||||
expose :name
|
||||
expose :title
|
||||
expose :description
|
||||
expose :total_projects_count
|
||||
expose :avatar_url do |topic, options|
|
||||
|
|
|
@ -38,7 +38,8 @@ module API
|
|||
success Entities::Projects::Topic
|
||||
end
|
||||
params do
|
||||
requires :name, type: String, desc: 'Name'
|
||||
requires :name, type: String, desc: 'Slug (name)'
|
||||
requires :title, type: String, desc: 'Title'
|
||||
optional :description, type: String, desc: 'Description'
|
||||
optional :avatar, type: ::API::Validations::Types::WorkhorseFile, desc: 'Avatar image for topic'
|
||||
end
|
||||
|
@ -60,7 +61,8 @@ module API
|
|||
end
|
||||
params do
|
||||
requires :id, type: Integer, desc: 'ID of project topic'
|
||||
optional :name, type: String, desc: 'Name'
|
||||
optional :name, type: String, desc: 'Slug (name)'
|
||||
optional :title, type: String, desc: 'Title'
|
||||
optional :description, type: String, desc: 'Description'
|
||||
optional :avatar, type: ::API::Validations::Types::WorkhorseFile, desc: 'Avatar image for topic'
|
||||
end
|
||||
|
|
28
lib/gitlab/background_migration/backfill_topics_title.rb
Normal file
28
lib/gitlab/background_migration/backfill_topics_title.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module BackgroundMigration
|
||||
# The class to backfill the topic title
|
||||
class BackfillTopicsTitle
|
||||
# Temporary AR model for topics
|
||||
class Topic < ActiveRecord::Base
|
||||
self.table_name = 'topics'
|
||||
end
|
||||
|
||||
def perform(start_id, end_id)
|
||||
Topic.where(id: start_id..end_id).where(title: nil).update_all('title = name')
|
||||
|
||||
mark_job_as_succeeded(start_id, end_id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def mark_job_as_succeeded(*arguments)
|
||||
::Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded(
|
||||
self.class.name.demodulize,
|
||||
arguments
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -6,7 +6,7 @@ After=network.target
|
|||
JoinsNamespaceOf=gitlab-puma.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Type=notify
|
||||
User=git
|
||||
WorkingDirectory=/home/git/gitlab
|
||||
Environment=RAILS_ENV=production
|
||||
|
@ -17,6 +17,7 @@ Restart=on-failure
|
|||
RestartSec=1
|
||||
SyslogIdentifier=gitlab-sidekiq
|
||||
Slice=gitlab.slice
|
||||
WatchdogSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=gitlab.target
|
||||
|
|
|
@ -28294,6 +28294,9 @@ msgstr ""
|
|||
msgid "Please fill in a name for your topic."
|
||||
msgstr ""
|
||||
|
||||
msgid "Please fill in a title for your topic."
|
||||
msgstr ""
|
||||
|
||||
msgid "Please fill out this field."
|
||||
msgstr ""
|
||||
|
||||
|
@ -39730,7 +39733,10 @@ msgstr ""
|
|||
msgid "Topic avatar for %{name} will be removed. This cannot be undone."
|
||||
msgstr ""
|
||||
|
||||
msgid "Topic name"
|
||||
msgid "Topic slug (name)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Topic title"
|
||||
msgstr ""
|
||||
|
||||
msgid "Topic was successfully updated."
|
||||
|
@ -45344,6 +45350,9 @@ msgstr ""
|
|||
msgid "my-channel"
|
||||
msgstr ""
|
||||
|
||||
msgid "my-topic"
|
||||
msgstr ""
|
||||
|
||||
msgid "need attention"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ module Trigger
|
|||
# Override to trigger and work with pipeline on different GitLab instance
|
||||
# type: :downstream -> downstream build and pipeline status
|
||||
# type: :upstream -> this project, e.g. for posting comments
|
||||
def gitlab_client(type)
|
||||
def gitlab_client(_type)
|
||||
# By default, always use the same client
|
||||
@gitlab_client ||= Gitlab.client(
|
||||
endpoint: 'https://gitlab.com/api/v4',
|
||||
|
@ -97,10 +97,15 @@ module Trigger
|
|||
end
|
||||
|
||||
# Must be overridden
|
||||
def ref
|
||||
def ref_param_name
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
# Can be overridden
|
||||
def primary_ref
|
||||
'main'
|
||||
end
|
||||
|
||||
# Can be overridden
|
||||
def trigger_token
|
||||
ENV['CI_JOB_TOKEN']
|
||||
|
@ -116,6 +121,27 @@ module Trigger
|
|||
ENV[version_file]&.strip || File.read(version_file).strip
|
||||
end
|
||||
|
||||
# Can be overridden
|
||||
def trigger_stable_branch_if_detected?
|
||||
false
|
||||
end
|
||||
|
||||
def stable_branch?
|
||||
ENV['CI_COMMIT_REF_NAME'] =~ /^[\d-]+-stable(-ee)?$/
|
||||
end
|
||||
|
||||
def fallback_ref
|
||||
if trigger_stable_branch_if_detected? && stable_branch?
|
||||
ENV['CI_COMMIT_REF_NAME'].delete_suffix('-ee')
|
||||
else
|
||||
primary_ref
|
||||
end
|
||||
end
|
||||
|
||||
def ref
|
||||
ENV.fetch(ref_param_name, fallback_ref)
|
||||
end
|
||||
|
||||
def base_variables
|
||||
# Use CI_MERGE_REQUEST_SOURCE_BRANCH_SHA for omnibus checkouts due to pipeline for merged results,
|
||||
# and fallback to CI_COMMIT_SHA for the `detached` pipelines.
|
||||
|
@ -146,8 +172,16 @@ module Trigger
|
|||
ENV.fetch('OMNIBUS_PROJECT_PATH', 'gitlab-org/build/omnibus-gitlab-mirror')
|
||||
end
|
||||
|
||||
def ref
|
||||
ENV.fetch('OMNIBUS_BRANCH', 'master')
|
||||
def ref_param_name
|
||||
'OMNIBUS_BRANCH'
|
||||
end
|
||||
|
||||
def primary_ref
|
||||
'master'
|
||||
end
|
||||
|
||||
def trigger_stable_branch_if_detected?
|
||||
true
|
||||
end
|
||||
|
||||
def extra_variables
|
||||
|
@ -184,10 +218,16 @@ module Trigger
|
|||
|
||||
private
|
||||
|
||||
def ref
|
||||
return ENV['CI_COMMIT_REF_NAME'] if ENV['CI_COMMIT_REF_NAME'] =~ /^[\d-]+-stable(-ee)?$/
|
||||
def ref_param_name
|
||||
'CNG_BRANCH'
|
||||
end
|
||||
|
||||
ENV.fetch('CNG_BRANCH', 'master')
|
||||
def primary_ref
|
||||
'master'
|
||||
end
|
||||
|
||||
def trigger_stable_branch_if_detected?
|
||||
true
|
||||
end
|
||||
|
||||
def extra_variables
|
||||
|
@ -272,8 +312,8 @@ module Trigger
|
|||
ENV.fetch('DOCS_PROJECT_PATH', 'gitlab-org/gitlab-docs')
|
||||
end
|
||||
|
||||
def ref
|
||||
ENV.fetch('DOCS_BRANCH', 'main')
|
||||
def ref_param_name
|
||||
'DOCS_BRANCH'
|
||||
end
|
||||
|
||||
# `gitlab-org/gitlab-docs` pipeline trigger "Triggered from gitlab-org/gitlab 'review-docs-deploy' job"
|
||||
|
@ -377,8 +417,12 @@ module Trigger
|
|||
}
|
||||
end
|
||||
|
||||
def ref
|
||||
ENV['GITLABCOM_DATABASE_TESTING_TRIGGER_REF'] || 'master'
|
||||
def ref_param_name
|
||||
'GITLABCOM_DATABASE_TESTING_TRIGGER_REF'
|
||||
end
|
||||
|
||||
def primary_ref
|
||||
'master'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -77,24 +77,31 @@ RSpec.describe Admin::TopicsController do
|
|||
describe 'POST #create' do
|
||||
it 'creates topic' do
|
||||
expect do
|
||||
post :create, params: { projects_topic: { name: 'test' } }
|
||||
post :create, params: { projects_topic: { name: 'test', title: 'Test' } }
|
||||
end.to change { Projects::Topic.count }.by(1)
|
||||
end
|
||||
|
||||
it 'shows error message for invalid topic' do
|
||||
post :create, params: { projects_topic: { name: nil } }
|
||||
it 'shows error message for invalid topic name' do
|
||||
post :create, params: { projects_topic: { name: nil, title: 'Test' } }
|
||||
|
||||
errors = assigns[:topic].errors
|
||||
expect(errors).to contain_exactly(errors.full_message(:name, I18n.t('errors.messages.blank')))
|
||||
end
|
||||
|
||||
it 'shows error message if topic not unique (case insensitive)' do
|
||||
post :create, params: { projects_topic: { name: topic.name.upcase } }
|
||||
it 'shows error message if topic name not unique (case insensitive)' do
|
||||
post :create, params: { projects_topic: { name: topic.name.upcase, title: topic.title } }
|
||||
|
||||
errors = assigns[:topic].errors
|
||||
expect(errors).to contain_exactly(errors.full_message(:name, I18n.t('errors.messages.taken')))
|
||||
end
|
||||
|
||||
it 'shows error message for invalid topic title' do
|
||||
post :create, params: { projects_topic: { name: 'test', title: nil } }
|
||||
|
||||
errors = assigns[:topic].errors
|
||||
expect(errors).to contain_exactly(errors.full_message(:title, I18n.t('errors.messages.blank')))
|
||||
end
|
||||
|
||||
context 'as a normal user' do
|
||||
before do
|
||||
sign_in(user)
|
||||
|
|
131
spec/db/docs_spec.rb
Normal file
131
spec/db/docs_spec.rb
Normal file
|
@ -0,0 +1,131 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Database Documentation' do
|
||||
context 'for each table' do
|
||||
let(:all_tables) do
|
||||
Gitlab::Database.database_base_models.flat_map { |_, m| m.connection.tables }.sort.uniq
|
||||
end
|
||||
|
||||
let(:metadata_required_fields) do
|
||||
%i(
|
||||
feature_categories
|
||||
table_name
|
||||
)
|
||||
end
|
||||
|
||||
let(:metadata_allowed_fields) do
|
||||
metadata_required_fields + %i(
|
||||
classes
|
||||
description
|
||||
introduced_by_url
|
||||
milestone
|
||||
)
|
||||
end
|
||||
|
||||
let(:metadata) do
|
||||
all_tables.each_with_object({}) do |table_name, hash|
|
||||
next unless File.exist?(table_metadata_file_path(table_name))
|
||||
|
||||
hash[table_name] ||= load_table_metadata(table_name)
|
||||
end
|
||||
end
|
||||
|
||||
let(:tables_without_metadata) do
|
||||
all_tables.reject { |t| metadata.has_key?(t) }
|
||||
end
|
||||
|
||||
let(:tables_without_valid_metadata) do
|
||||
metadata.select { |_, t| t.has_key?(:error) }.keys
|
||||
end
|
||||
|
||||
let(:tables_with_disallowed_fields) do
|
||||
metadata.select { |_, t| t.has_key?(:disallowed_fields) }.keys
|
||||
end
|
||||
|
||||
let(:tables_with_missing_required_fields) do
|
||||
metadata.select { |_, t| t.has_key?(:missing_required_fields) }.keys
|
||||
end
|
||||
|
||||
it 'has a metadata file' do
|
||||
expect(tables_without_metadata).to be_empty, multiline_error(
|
||||
'Missing metadata files',
|
||||
tables_without_metadata.map { |t| " #{table_metadata_file(t)}" }
|
||||
)
|
||||
end
|
||||
|
||||
it 'has a valid metadata file' do
|
||||
expect(tables_without_valid_metadata).to be_empty, table_metadata_errors(
|
||||
'Table metadata files with errors',
|
||||
:error,
|
||||
tables_without_valid_metadata
|
||||
)
|
||||
end
|
||||
|
||||
it 'has a valid metadata file with allowed fields' do
|
||||
expect(tables_with_disallowed_fields).to be_empty, table_metadata_errors(
|
||||
'Table metadata files with disallowed fields',
|
||||
:disallowed_fields,
|
||||
tables_with_disallowed_fields
|
||||
)
|
||||
end
|
||||
|
||||
it 'has a valid metadata file without missing fields' do
|
||||
expect(tables_with_missing_required_fields).to be_empty, table_metadata_errors(
|
||||
'Table metadata files with missing fields',
|
||||
:missing_required_fields,
|
||||
tables_with_missing_required_fields
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def table_metadata_file(table_name)
|
||||
File.join('db', 'docs', "#{table_name}.yml")
|
||||
end
|
||||
|
||||
def table_metadata_file_path(table_name)
|
||||
Rails.root.join(table_metadata_file(table_name))
|
||||
end
|
||||
|
||||
def load_table_metadata(table_name)
|
||||
result = {}
|
||||
begin
|
||||
result[:metadata] = YAML.safe_load(File.read(table_metadata_file_path(table_name))).deep_symbolize_keys
|
||||
|
||||
disallowed_fields = (result[:metadata].keys - metadata_allowed_fields)
|
||||
unless disallowed_fields.empty?
|
||||
result[:disallowed_fields] = "fields not allowed: #{disallowed_fields.join(', ')}"
|
||||
end
|
||||
|
||||
missing_required_fields = (metadata_required_fields - result[:metadata].reject { |_, v| v.blank? }.keys)
|
||||
unless missing_required_fields.empty?
|
||||
result[:missing_required_fields] = "missing required fields: #{missing_required_fields.join(', ')}"
|
||||
end
|
||||
rescue Psych::SyntaxError => ex
|
||||
result[:error] = ex.message
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def table_metadata_errors(title, field, tables)
|
||||
lines = tables.map do |table_name|
|
||||
<<~EOM
|
||||
#{table_metadata_file(table_name)}
|
||||
#{metadata[table_name][field]}
|
||||
EOM
|
||||
end
|
||||
|
||||
multiline_error(title, lines)
|
||||
end
|
||||
|
||||
def multiline_error(title, lines)
|
||||
<<~EOM
|
||||
#{title}:
|
||||
|
||||
#{lines.join("\n")}
|
||||
EOM
|
||||
end
|
||||
end
|
|
@ -3,5 +3,6 @@
|
|||
FactoryBot.define do
|
||||
factory :topic, class: 'Projects::Topic' do
|
||||
name { generate(:name) }
|
||||
title { generate(:title) }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,6 +11,7 @@ RSpec.describe API::Entities::Projects::Topic do
|
|||
expect(subject).to include(
|
||||
:id,
|
||||
:name,
|
||||
:title,
|
||||
:description,
|
||||
:total_projects_count,
|
||||
:avatar_url
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BackgroundMigration::BackfillTopicsTitle, schema: 20220331133802 do
|
||||
it 'correctly backfills the title of the topics' do
|
||||
topics = table(:topics)
|
||||
|
||||
topic_1 = topics.create!(name: 'topic1')
|
||||
topic_2 = topics.create!(name: 'topic2', title: 'Topic 2')
|
||||
topic_3 = topics.create!(name: 'topic3')
|
||||
topic_4 = topics.create!(name: 'topic4')
|
||||
|
||||
subject.perform(topic_1.id, topic_3.id)
|
||||
|
||||
expect(topic_1.reload.title).to eq('topic1')
|
||||
expect(topic_2.reload.title).to eq('Topic 2')
|
||||
expect(topic_3.reload.title).to eq('topic3')
|
||||
expect(topic_4.reload.title).to be_nil
|
||||
end
|
||||
end
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BackgroundMigration::MergeTopicsWithSameName, schema: 20220223124428 do
|
||||
RSpec.describe Gitlab::BackgroundMigration::MergeTopicsWithSameName, schema: 20220331133802 do
|
||||
def set_avatar(topic_id, avatar)
|
||||
topic = ::Projects::Topic.find(topic_id)
|
||||
topic.avatar = avatar
|
||||
|
@ -16,49 +16,62 @@ RSpec.describe Gitlab::BackgroundMigration::MergeTopicsWithSameName, schema: 202
|
|||
topics = table(:topics)
|
||||
project_topics = table(:project_topics)
|
||||
|
||||
group = namespaces.create!(name: 'group', path: 'group')
|
||||
project_1 = projects.create!(namespace_id: group.id, visibility_level: 20)
|
||||
project_2 = projects.create!(namespace_id: group.id, visibility_level: 10)
|
||||
project_3 = projects.create!(namespace_id: group.id, visibility_level: 0)
|
||||
group_1 = namespaces.create!(name: 'space1', type: 'Group', path: 'space1')
|
||||
group_2 = namespaces.create!(name: 'space2', type: 'Group', path: 'space2')
|
||||
group_3 = namespaces.create!(name: 'space3', type: 'Group', path: 'space3')
|
||||
proj_space_1 = namespaces.create!(name: 'proj1', path: 'proj1', type: 'Project', parent_id: group_1.id)
|
||||
proj_space_2 = namespaces.create!(name: 'proj2', path: 'proj2', type: 'Project', parent_id: group_2.id)
|
||||
proj_space_3 = namespaces.create!(name: 'proj3', path: 'proj3', type: 'Project', parent_id: group_3.id)
|
||||
project_1 = projects.create!(namespace_id: group_1.id, project_namespace_id: proj_space_1.id, visibility_level: 20)
|
||||
project_2 = projects.create!(namespace_id: group_2.id, project_namespace_id: proj_space_2.id, visibility_level: 10)
|
||||
project_3 = projects.create!(namespace_id: group_3.id, project_namespace_id: proj_space_3.id, visibility_level: 0)
|
||||
topic_1_keep = topics.create!(
|
||||
name: 'topic1',
|
||||
title: 'Topic 1',
|
||||
description: 'description 1 to keep',
|
||||
total_projects_count: 2,
|
||||
non_private_projects_count: 2
|
||||
)
|
||||
topic_1_remove = topics.create!(
|
||||
name: 'TOPIC1',
|
||||
title: 'Topic 1',
|
||||
description: 'description 1 to remove',
|
||||
total_projects_count: 2,
|
||||
non_private_projects_count: 1
|
||||
)
|
||||
topic_2_remove = topics.create!(
|
||||
name: 'topic2',
|
||||
title: 'Topic 2',
|
||||
total_projects_count: 0
|
||||
)
|
||||
topic_2_keep = topics.create!(
|
||||
name: 'TOPIC2',
|
||||
title: 'Topic 2',
|
||||
description: 'description 2 to keep',
|
||||
total_projects_count: 1
|
||||
)
|
||||
topic_3_remove_1 = topics.create!(
|
||||
name: 'topic3',
|
||||
title: 'Topic 3',
|
||||
total_projects_count: 2,
|
||||
non_private_projects_count: 1
|
||||
)
|
||||
topic_3_keep = topics.create!(
|
||||
name: 'Topic3',
|
||||
title: 'Topic 3',
|
||||
total_projects_count: 2,
|
||||
non_private_projects_count: 2
|
||||
)
|
||||
topic_3_remove_2 = topics.create!(
|
||||
name: 'TOPIC3',
|
||||
title: 'Topic 3',
|
||||
description: 'description 3 to keep',
|
||||
total_projects_count: 2,
|
||||
non_private_projects_count: 1
|
||||
)
|
||||
topic_4_keep = topics.create!(
|
||||
name: 'topic4'
|
||||
name: 'topic4',
|
||||
title: 'Topic 4'
|
||||
)
|
||||
|
||||
project_topics_1 = []
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!
|
||||
|
||||
RSpec.describe ScheduleBackfillTopicsTitle do
|
||||
let(:topics) { table(:topics) }
|
||||
|
||||
let!(:topic1) { topics.create!(name: 'topic1') }
|
||||
let!(:topic2) { topics.create!(name: 'topic2') }
|
||||
let!(:topic3) { topics.create!(name: 'topic3') }
|
||||
|
||||
it 'correctly schedules background migrations', :aggregate_failures do
|
||||
stub_const("#{Gitlab::Database::Migrations::BackgroundMigrationHelpers}::BATCH_SIZE", 2)
|
||||
|
||||
Sidekiq::Testing.fake! do
|
||||
freeze_time do
|
||||
migrate!
|
||||
|
||||
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, topic1.id, topic2.id)
|
||||
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, topic3.id, topic3.id)
|
||||
expect(BackgroundMigrationWorker.jobs.size).to eq(2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -25,6 +25,8 @@ RSpec.describe Projects::Topic do
|
|||
it { is_expected.to validate_uniqueness_of(:name).case_insensitive }
|
||||
it { is_expected.to validate_length_of(:name).is_at_most(255) }
|
||||
it { is_expected.to validate_length_of(:description).is_at_most(1024) }
|
||||
it { expect(Projects::Topic.new).to validate_presence_of(:title) }
|
||||
it { expect(Projects::Topic.new).to validate_length_of(:title).is_at_most(255) }
|
||||
end
|
||||
|
||||
describe 'scopes' do
|
||||
|
|
|
@ -117,7 +117,7 @@ RSpec.describe API::Topics do
|
|||
describe 'POST /topics', :aggregate_failures do
|
||||
context 'as administrator' do
|
||||
it 'creates a topic' do
|
||||
post api('/topics/', admin), params: { name: 'my-topic' }
|
||||
post api('/topics/', admin), params: { name: 'my-topic', title: 'My Topic' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:created)
|
||||
expect(json_response['name']).to eq('my-topic')
|
||||
|
@ -128,7 +128,7 @@ RSpec.describe API::Topics do
|
|||
workhorse_form_with_file(
|
||||
api('/topics/', admin),
|
||||
file_key: :avatar,
|
||||
params: { name: 'my-topic', description: 'my description...', avatar: file }
|
||||
params: { name: 'my-topic', title: 'My Topic', description: 'my description...', avatar: file }
|
||||
)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:created)
|
||||
|
@ -137,23 +137,30 @@ RSpec.describe API::Topics do
|
|||
end
|
||||
|
||||
it 'returns 400 if name is missing' do
|
||||
post api('/topics/', admin)
|
||||
post api('/topics/', admin), params: { title: 'My Topic' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response['error']).to eql('name is missing')
|
||||
end
|
||||
|
||||
it 'returns 400 if name is not unique (case insensitive)' do
|
||||
post api('/topics/', admin), params: { name: topic_1.name.downcase }
|
||||
post api('/topics/', admin), params: { name: topic_1.name.downcase, title: 'My Topic' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response['message']['name']).to eq(['has already been taken'])
|
||||
end
|
||||
|
||||
it 'returns 400 if title is missing' do
|
||||
post api('/topics/', admin), params: { name: 'my-topic' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response['error']).to eql('title is missing')
|
||||
end
|
||||
end
|
||||
|
||||
context 'as normal user' do
|
||||
it 'returns 403 Forbidden' do
|
||||
post api('/topics/', user), params: { name: 'my-topic' }
|
||||
post api('/topics/', user), params: { name: 'my-topic', title: 'My Topic' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
end
|
||||
|
@ -161,7 +168,7 @@ RSpec.describe API::Topics do
|
|||
|
||||
context 'as anonymous' do
|
||||
it 'returns 401 Unauthorized' do
|
||||
post api('/topics/'), params: { name: 'my-topic' }
|
||||
post api('/topics/'), params: { name: 'my-topic', title: 'My Topic' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
end
|
||||
|
|
936
spec/scripts/trigger-build_spec.rb
Normal file
936
spec/scripts/trigger-build_spec.rb
Normal file
|
@ -0,0 +1,936 @@
|
|||
# frozen_string_literal: true
|
||||
# rubocop:disable RSpec/VerifiedDoubles
|
||||
|
||||
require 'fast_spec_helper'
|
||||
require 'rspec-parameterized'
|
||||
|
||||
require_relative '../../scripts/trigger-build'
|
||||
|
||||
RSpec.describe Trigger do
|
||||
let(:env) do
|
||||
{
|
||||
'CI_JOB_URL' => 'ci_job_url',
|
||||
'CI_PROJECT_PATH' => 'ci_project_path',
|
||||
'CI_COMMIT_REF_NAME' => 'ci_commit_ref_name',
|
||||
'CI_COMMIT_REF_SLUG' => 'ci_commit_ref_slug',
|
||||
'CI_COMMIT_SHA' => 'ci_commit_sha',
|
||||
'CI_MERGE_REQUEST_PROJECT_ID' => 'ci_merge_request_project_id',
|
||||
'CI_MERGE_REQUEST_IID' => 'ci_merge_request_iid',
|
||||
'GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN' => 'bot-token',
|
||||
'CI_JOB_TOKEN' => 'job-token',
|
||||
'GITLAB_USER_NAME' => 'gitlab_user_name',
|
||||
'GITLAB_USER_LOGIN' => 'gitlab_user_login',
|
||||
'QA_IMAGE' => 'qa_image'
|
||||
}
|
||||
end
|
||||
|
||||
let(:stubbed_downstream_gitlab_client) { double('downstream_gitlab_api_client') }
|
||||
let(:gitlab_client_private_token) { env['GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN'] }
|
||||
let(:stubbed_pipeline) { Struct.new(:id, :web_url).new(42, 'pipeline_url') }
|
||||
let(:trigger_token) { env['CI_JOB_TOKEN'] }
|
||||
let(:api_endpoint) { 'https://gitlab.com/api/v4' }
|
||||
|
||||
before do
|
||||
stub_env(env)
|
||||
allow(subject).to receive(:puts)
|
||||
allow(Gitlab).to receive(:client)
|
||||
.with(
|
||||
endpoint: api_endpoint,
|
||||
private_token: gitlab_client_private_token
|
||||
)
|
||||
.and_return(stubbed_downstream_gitlab_client)
|
||||
end
|
||||
|
||||
def expect_run_trigger_with_params(variables = {})
|
||||
expect(stubbed_downstream_gitlab_client).to receive(:run_trigger)
|
||||
.with(
|
||||
downstream_project_path,
|
||||
trigger_token,
|
||||
ref,
|
||||
hash_including(variables)
|
||||
)
|
||||
.and_return(stubbed_pipeline)
|
||||
end
|
||||
|
||||
describe Trigger::Base do
|
||||
let(:ref) { 'main' }
|
||||
|
||||
describe '#invoke!' do
|
||||
context "when required methods aren't defined" do
|
||||
it 'raises a NotImplementedError' do
|
||||
expect { described_class.new.invoke! }.to raise_error(NotImplementedError)
|
||||
end
|
||||
end
|
||||
|
||||
context "when required methods are defined" do
|
||||
let(:downstream_project_path) { 'foo/bar' }
|
||||
let(:subclass) do
|
||||
Class.new(Trigger::Base) do
|
||||
def downstream_project_path
|
||||
'foo/bar'
|
||||
end
|
||||
|
||||
# Must be overridden
|
||||
def ref_param_name
|
||||
'FOO_BAR_BRANCH'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
subject { subclass.new }
|
||||
|
||||
context 'when env variable `FOO_BAR_BRANCH` does not exist' do
|
||||
it 'triggers the pipeline on the correct project and branch' do
|
||||
expect_run_trigger_with_params
|
||||
|
||||
subject.invoke!
|
||||
end
|
||||
end
|
||||
|
||||
context 'when env variable `FOO_BAR_BRANCH` exists' do
|
||||
let(:ref) { 'foo_bar_branch' }
|
||||
|
||||
before do
|
||||
stub_env('FOO_BAR_BRANCH', ref)
|
||||
end
|
||||
|
||||
it 'triggers the pipeline on the correct project and branch' do
|
||||
expect_run_trigger_with_params
|
||||
|
||||
subject.invoke!
|
||||
end
|
||||
end
|
||||
|
||||
it 'waits for downstream pipeline' do
|
||||
expect_run_trigger_with_params
|
||||
expect(Trigger::Pipeline).to receive(:new)
|
||||
.with(downstream_project_path, stubbed_pipeline.id, stubbed_downstream_gitlab_client)
|
||||
|
||||
subject.invoke!
|
||||
end
|
||||
|
||||
context 'with post_comment: true' do
|
||||
before do
|
||||
stub_env('CI_COMMIT_REF_NAME', "#{ref}-ee")
|
||||
end
|
||||
|
||||
it 'posts a comment' do
|
||||
expect_run_trigger_with_params
|
||||
expect(Trigger::CommitComment).to receive(:post!).with(stubbed_pipeline, stubbed_downstream_gitlab_client)
|
||||
|
||||
subject.invoke!(post_comment: true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with downstream_job_name: "foo"' do
|
||||
let(:downstream_job) { Struct.new(:id, :name).new(42, 'foo') }
|
||||
let(:paginated_resources) { Struct.new(:auto_paginate).new([downstream_job]) }
|
||||
|
||||
before do
|
||||
stub_env('CI_COMMIT_REF_NAME', "#{ref}-ee")
|
||||
end
|
||||
|
||||
it 'fetches the downstream job' do
|
||||
expect_run_trigger_with_params
|
||||
expect(stubbed_downstream_gitlab_client).to receive(:pipeline_jobs)
|
||||
.with(downstream_project_path, stubbed_pipeline.id).and_return(paginated_resources)
|
||||
expect(Trigger::Job).to receive(:new)
|
||||
.with(downstream_project_path, downstream_job.id, stubbed_downstream_gitlab_client)
|
||||
|
||||
subject.invoke!(downstream_job_name: 'foo')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#variables' do
|
||||
let(:simple_forwarded_variables) do
|
||||
{
|
||||
'TRIGGER_SOURCE' => env['CI_JOB_URL'],
|
||||
'TOP_UPSTREAM_SOURCE_PROJECT' => env['CI_PROJECT_PATH'],
|
||||
'TOP_UPSTREAM_SOURCE_REF' => env['CI_COMMIT_REF_NAME'],
|
||||
'TOP_UPSTREAM_SOURCE_JOB' => env['CI_JOB_URL'],
|
||||
'TOP_UPSTREAM_MERGE_REQUEST_PROJECT_ID' => env['CI_MERGE_REQUEST_PROJECT_ID'],
|
||||
'TOP_UPSTREAM_MERGE_REQUEST_IID' => env['CI_MERGE_REQUEST_IID']
|
||||
}
|
||||
end
|
||||
|
||||
it 'includes simple forwarded variables' do
|
||||
expect(subject.variables).to include(simple_forwarded_variables)
|
||||
end
|
||||
|
||||
describe "#base_variables" do
|
||||
context 'when CI_COMMIT_TAG is set' do
|
||||
before do
|
||||
stub_env('CI_COMMIT_TAG', 'v1.0')
|
||||
end
|
||||
|
||||
it 'sets GITLAB_REF_SLUG to CI_COMMIT_REF_NAME' do
|
||||
expect(subject.variables['GITLAB_REF_SLUG']).to eq(env['CI_COMMIT_REF_NAME'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_COMMIT_TAG is nil' do
|
||||
before do
|
||||
stub_env('CI_COMMIT_TAG', nil)
|
||||
end
|
||||
|
||||
it 'sets GITLAB_REF_SLUG to CI_COMMIT_REF_SLUG' do
|
||||
expect(subject.variables['GITLAB_REF_SLUG']).to eq(env['CI_COMMIT_REF_SLUG'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when TRIGGERED_USER is set' do
|
||||
before do
|
||||
stub_env('TRIGGERED_USER', 'triggered_user')
|
||||
end
|
||||
|
||||
it 'sets TRIGGERED_USER to triggered_user' do
|
||||
expect(subject.variables['TRIGGERED_USER']).to eq('triggered_user')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when TRIGGERED_USER is not set' do
|
||||
before do
|
||||
stub_env('TRIGGERED_USER', nil)
|
||||
end
|
||||
|
||||
it 'sets TRIGGERED_USER to GITLAB_USER_NAME' do
|
||||
expect(subject.variables['TRIGGERED_USER']).to eq(env['GITLAB_USER_NAME'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_SOURCE_BRANCH_SHA is set' do
|
||||
before do
|
||||
stub_env('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', 'ci_merge_request_source_branch_sha')
|
||||
end
|
||||
|
||||
it 'sets TOP_UPSTREAM_SOURCE_SHA to ci_merge_request_source_branch_sha' do
|
||||
expect(subject.variables['TOP_UPSTREAM_SOURCE_SHA']).to eq('ci_merge_request_source_branch_sha')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_SOURCE_BRANCH_SHA is set as empty' do
|
||||
before do
|
||||
stub_env('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', '')
|
||||
end
|
||||
|
||||
it 'sets TOP_UPSTREAM_SOURCE_SHA to CI_COMMIT_SHA' do
|
||||
expect(subject.variables['TOP_UPSTREAM_SOURCE_SHA']).to eq(env['CI_COMMIT_SHA'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_SOURCE_BRANCH_SHA is not set' do
|
||||
before do
|
||||
stub_env('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', nil)
|
||||
end
|
||||
|
||||
it 'sets TOP_UPSTREAM_SOURCE_SHA to CI_COMMIT_SHA' do
|
||||
expect(subject.variables['TOP_UPSTREAM_SOURCE_SHA']).to eq(env['CI_COMMIT_SHA'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#version_file_variables" do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:version_file, :version) do
|
||||
'GITALY_SERVER_VERSION' | "1"
|
||||
'GITLAB_ELASTICSEARCH_INDEXER_VERSION' | "2"
|
||||
'GITLAB_KAS_VERSION' | "3"
|
||||
'GITLAB_PAGES_VERSION' | "4"
|
||||
'GITLAB_SHELL_VERSION' | "5"
|
||||
'GITLAB_WORKHORSE_VERSION' | "6"
|
||||
end
|
||||
|
||||
with_them do
|
||||
context "when set in ENV" do
|
||||
before do
|
||||
stub_env(version_file, version)
|
||||
end
|
||||
|
||||
it 'includes the version from ENV' do
|
||||
expect(subject.variables[version_file]).to eq(version)
|
||||
end
|
||||
end
|
||||
|
||||
context "when set in a file" do
|
||||
before do
|
||||
allow(File).to receive(:read).and_call_original
|
||||
end
|
||||
|
||||
it 'includes the version from the file' do
|
||||
expect(File).to receive(:read).with(version_file).and_return(version)
|
||||
expect(subject.variables[version_file]).to eq(version)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Trigger::Omnibus do
|
||||
describe '#variables' do
|
||||
it 'invokes the trigger with expected variables' do
|
||||
expect(subject.variables).to include(
|
||||
'QA_IMAGE' => env['QA_IMAGE'],
|
||||
'SKIP_QA_DOCKER' => 'true',
|
||||
'ALTERNATIVE_SOURCES' => 'true',
|
||||
'CACHE_UPDATE' => env['OMNIBUS_GITLAB_CACHE_UPDATE'],
|
||||
'GITLAB_QA_OPTIONS' => env['GITLAB_QA_OPTIONS'],
|
||||
'QA_TESTS' => env['QA_TESTS'],
|
||||
'ALLURE_JOB_NAME' => env['ALLURE_JOB_NAME']
|
||||
)
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_SOURCE_BRANCH_SHA is set' do
|
||||
before do
|
||||
stub_env('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', 'ci_merge_request_source_branch_sha')
|
||||
end
|
||||
|
||||
it 'sets GITLAB_VERSION & IMAGE_TAG to ci_merge_request_source_branch_sha' do
|
||||
expect(subject.variables).to include(
|
||||
'GITLAB_VERSION' => 'ci_merge_request_source_branch_sha',
|
||||
'IMAGE_TAG' => 'ci_merge_request_source_branch_sha'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_SOURCE_BRANCH_SHA is set as empty' do
|
||||
before do
|
||||
stub_env('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', '')
|
||||
end
|
||||
|
||||
it 'sets GITLAB_VERSION & IMAGE_TAG to CI_COMMIT_SHA' do
|
||||
expect(subject.variables).to include(
|
||||
'GITLAB_VERSION' => env['CI_COMMIT_SHA'],
|
||||
'IMAGE_TAG' => env['CI_COMMIT_SHA']
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_SOURCE_BRANCH_SHA is not set' do
|
||||
before do
|
||||
stub_env('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', nil)
|
||||
end
|
||||
|
||||
it 'sets GITLAB_VERSION & IMAGE_TAG to CI_COMMIT_SHA' do
|
||||
expect(subject.variables).to include(
|
||||
'GITLAB_VERSION' => env['CI_COMMIT_SHA'],
|
||||
'IMAGE_TAG' => env['CI_COMMIT_SHA']
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when Trigger.security? is true' do
|
||||
before do
|
||||
allow(Trigger).to receive(:security?).and_return(true)
|
||||
end
|
||||
|
||||
it 'sets SECURITY_SOURCES to true' do
|
||||
expect(subject.variables['SECURITY_SOURCES']).to eq('true')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when Trigger.security? is false' do
|
||||
before do
|
||||
allow(Trigger).to receive(:security?).and_return(false)
|
||||
end
|
||||
|
||||
it 'sets SECURITY_SOURCES to false' do
|
||||
expect(subject.variables['SECURITY_SOURCES']).to eq('false')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when Trigger.ee? is true' do
|
||||
before do
|
||||
allow(Trigger).to receive(:ee?).and_return(true)
|
||||
end
|
||||
|
||||
it 'sets ee to true' do
|
||||
expect(subject.variables['ee']).to eq('true')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when Trigger.ee? is false' do
|
||||
before do
|
||||
allow(Trigger).to receive(:ee?).and_return(false)
|
||||
end
|
||||
|
||||
it 'sets ee to false' do
|
||||
expect(subject.variables['ee']).to eq('false')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when QA_BRANCH is set' do
|
||||
before do
|
||||
stub_env('QA_BRANCH', 'qa_branch')
|
||||
end
|
||||
|
||||
it 'sets QA_BRANCH to qa_branch' do
|
||||
expect(subject.variables['QA_BRANCH']).to eq('qa_branch')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.access_token' do
|
||||
context 'when OMNIBUS_GITLAB_PROJECT_ACCESS_TOKEN is set' do
|
||||
let(:omnibus_gitlab_project_access_token) { 'omnibus_gitlab_project_access_token' }
|
||||
|
||||
before do
|
||||
stub_env('OMNIBUS_GITLAB_PROJECT_ACCESS_TOKEN', omnibus_gitlab_project_access_token)
|
||||
end
|
||||
|
||||
it 'returns the omnibus-specific access token' do
|
||||
expect(described_class.access_token).to eq(omnibus_gitlab_project_access_token)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when OMNIBUS_GITLAB_PROJECT_ACCESS_TOKEN is not set' do
|
||||
before do
|
||||
stub_env('OMNIBUS_GITLAB_PROJECT_ACCESS_TOKEN', nil)
|
||||
end
|
||||
|
||||
it 'returns the default access token' do
|
||||
expect(described_class.access_token).to eq(Trigger::Base.access_token)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#invoke!' do
|
||||
let(:downstream_project_path) { 'gitlab-org/build/omnibus-gitlab-mirror' }
|
||||
let(:ref) { 'master' }
|
||||
|
||||
let(:env) do
|
||||
super().merge(
|
||||
'QA_IMAGE' => 'qa_image',
|
||||
'OMNIBUS_GITLAB_PROJECT_ACCESS_TOKEN' => nil,
|
||||
'OMNIBUS_GITLAB_CACHE_UPDATE' => 'omnibus_gitlab_cache_update',
|
||||
'GITLAB_QA_OPTIONS' => 'gitlab_qa_options',
|
||||
'QA_TESTS' => 'qa_tests',
|
||||
'ALLURE_JOB_NAME' => 'allure_job_name'
|
||||
)
|
||||
end
|
||||
|
||||
describe '#downstream_project_path' do
|
||||
context 'when OMNIBUS_PROJECT_PATH is set' do
|
||||
let(:downstream_project_path) { 'omnibus_project_path' }
|
||||
|
||||
before do
|
||||
stub_env('OMNIBUS_PROJECT_PATH', downstream_project_path)
|
||||
end
|
||||
|
||||
it 'triggers the pipeline on the correct project' do
|
||||
expect_run_trigger_with_params
|
||||
|
||||
subject.invoke!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#ref' do
|
||||
context 'when OMNIBUS_BRANCH is set' do
|
||||
let(:ref) { 'omnibus_branch' }
|
||||
|
||||
before do
|
||||
stub_env('OMNIBUS_BRANCH', ref)
|
||||
end
|
||||
|
||||
it 'triggers the pipeline on the correct ref' do
|
||||
expect_run_trigger_with_params
|
||||
|
||||
subject.invoke!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_COMMIT_REF_NAME is a stable branch' do
|
||||
let(:ref) { '14-10-stable' }
|
||||
|
||||
before do
|
||||
stub_env('CI_COMMIT_REF_NAME', "#{ref}-ee")
|
||||
end
|
||||
|
||||
it 'triggers the pipeline on the correct ref' do
|
||||
expect_run_trigger_with_params
|
||||
|
||||
subject.invoke!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Trigger::CNG do
|
||||
describe '#variables' do
|
||||
it 'does not include redundant variables' do
|
||||
expect(subject.variables).not_to include('TRIGGER_SOURCE', 'TRIGGERED_USER')
|
||||
end
|
||||
|
||||
it 'invokes the trigger with expected variables' do
|
||||
expect(subject.variables).to include('FORCE_RAILS_IMAGE_BUILDS' => 'true')
|
||||
end
|
||||
|
||||
describe "TRIGGER_BRANCH" do
|
||||
context 'when CNG_BRANCH is not set' do
|
||||
it 'sets TRIGGER_BRANCH to master' do
|
||||
expect(subject.variables['TRIGGER_BRANCH']).to eq('master')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CNG_BRANCH is set' do
|
||||
let(:ref) { 'cng_branch' }
|
||||
|
||||
before do
|
||||
stub_env('CNG_BRANCH', ref)
|
||||
end
|
||||
|
||||
it 'sets TRIGGER_BRANCH to cng_branch' do
|
||||
expect(subject.variables['TRIGGER_BRANCH']).to eq(ref)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_COMMIT_REF_NAME is a stable branch' do
|
||||
let(:ref) { '14-10-stable' }
|
||||
|
||||
before do
|
||||
stub_env('CI_COMMIT_REF_NAME', "#{ref}-ee")
|
||||
end
|
||||
|
||||
it 'sets TRIGGER_BRANCH to the corresponding stable branch' do
|
||||
expect(subject.variables['TRIGGER_BRANCH']).to eq(ref)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "GITLAB_VERSION" do
|
||||
context 'when CI_MERGE_REQUEST_SOURCE_BRANCH_SHA is set' do
|
||||
before do
|
||||
stub_env('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', 'ci_merge_request_source_branch_sha')
|
||||
end
|
||||
|
||||
it 'sets GITLAB_VERSION to CI_MERGE_REQUEST_SOURCE_BRANCH_SHA' do
|
||||
expect(subject.variables['GITLAB_VERSION']).to eq('ci_merge_request_source_branch_sha')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_SOURCE_BRANCH_SHA is set as empty' do
|
||||
before do
|
||||
stub_env('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', '')
|
||||
end
|
||||
|
||||
it 'sets GITLAB_VERSION to CI_COMMIT_SHA' do
|
||||
expect(subject.variables['GITLAB_VERSION']).to eq(env['CI_COMMIT_SHA'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_SOURCE_BRANCH_SHA is not set' do
|
||||
before do
|
||||
stub_env('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', nil)
|
||||
end
|
||||
|
||||
it 'sets GITLAB_VERSION to CI_COMMIT_SHA' do
|
||||
expect(subject.variables['GITLAB_VERSION']).to eq(env['CI_COMMIT_SHA'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "GITLAB_TAG" do
|
||||
context 'when CI_COMMIT_TAG is set' do
|
||||
before do
|
||||
stub_env('CI_COMMIT_TAG', 'v1.0')
|
||||
end
|
||||
|
||||
it 'sets GITLAB_TAG to true' do
|
||||
expect(subject.variables['GITLAB_TAG']).to eq('v1.0')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_COMMIT_TAG is nil' do
|
||||
before do
|
||||
stub_env('CI_COMMIT_TAG', nil)
|
||||
end
|
||||
|
||||
it 'sets GITLAB_TAG to nil' do
|
||||
expect(subject.variables['GITLAB_TAG']).to eq(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "GITLAB_ASSETS_TAG" do
|
||||
context 'when CI_COMMIT_TAG is set' do
|
||||
before do
|
||||
stub_env('CI_COMMIT_TAG', 'v1.0')
|
||||
end
|
||||
|
||||
it 'sets GITLAB_ASSETS_TAG to CI_COMMIT_REF_NAME' do
|
||||
expect(subject.variables['GITLAB_ASSETS_TAG']).to eq(env['CI_COMMIT_REF_NAME'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_COMMIT_TAG and CI_MERGE_REQUEST_SOURCE_BRANCH_SHA are nil' do
|
||||
before do
|
||||
stub_env('CI_COMMIT_TAG', nil)
|
||||
stub_env('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', nil)
|
||||
end
|
||||
|
||||
it 'sets GITLAB_ASSETS_TAG to CI_COMMIT_SHA' do
|
||||
expect(subject.variables['GITLAB_ASSETS_TAG']).to eq(env['CI_COMMIT_SHA'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "CE_PIPELINE" do
|
||||
context 'when Trigger.ee? is true' do
|
||||
before do
|
||||
allow(Trigger).to receive(:ee?).and_return(true)
|
||||
end
|
||||
|
||||
it 'sets CE_PIPELINE to nil' do
|
||||
expect(subject.variables['CE_PIPELINE']).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when Trigger.ee? is false' do
|
||||
before do
|
||||
allow(Trigger).to receive(:ee?).and_return(false)
|
||||
end
|
||||
|
||||
it 'sets CE_PIPELINE to true' do
|
||||
expect(subject.variables['CE_PIPELINE']).to eq('true')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "EE_PIPELINE" do
|
||||
context 'when Trigger.ee? is true' do
|
||||
before do
|
||||
allow(Trigger).to receive(:ee?).and_return(true)
|
||||
end
|
||||
|
||||
it 'sets EE_PIPELINE to true' do
|
||||
expect(subject.variables['EE_PIPELINE']).to eq('true')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when Trigger.ee? is false' do
|
||||
before do
|
||||
allow(Trigger).to receive(:ee?).and_return(false)
|
||||
end
|
||||
|
||||
it 'sets EE_PIPELINE to nil' do
|
||||
expect(subject.variables['EE_PIPELINE']).to eq(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#version_param_value" do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let(:version_file) { 'GITALY_SERVER_VERSION' }
|
||||
|
||||
where(:raw_version, :expected_version) do
|
||||
"1.2.3" | "v1.2.3"
|
||||
"1.2.3-rc1" | "v1.2.3-rc1"
|
||||
"1.2.3-ee" | "v1.2.3-ee"
|
||||
"1.2.3-rc1-ee" | "v1.2.3-rc1-ee"
|
||||
end
|
||||
|
||||
with_them do
|
||||
context "when set in ENV" do
|
||||
before do
|
||||
stub_env(version_file, raw_version)
|
||||
end
|
||||
|
||||
it 'includes the version from ENV' do
|
||||
expect(subject.variables[version_file]).to eq(expected_version)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Trigger::Docs do
|
||||
describe '#variables' do
|
||||
describe "BRANCH_CE" do
|
||||
before do
|
||||
stub_env('CI_PROJECT_PATH', 'gitlab-org/gitlab-foss')
|
||||
end
|
||||
|
||||
context 'when CI_PROJECT_PATH is gitlab-org/gitlab-foss' do
|
||||
it 'sets BRANCH_CE to CI_COMMIT_REF_NAME' do
|
||||
expect(subject.variables['BRANCH_CE']).to eq(env['CI_COMMIT_REF_NAME'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "BRANCH_EE" do
|
||||
before do
|
||||
stub_env('CI_PROJECT_PATH', 'gitlab-org/gitlab')
|
||||
end
|
||||
|
||||
context 'when CI_PROJECT_PATH is gitlab-org/gitlab' do
|
||||
it 'sets BRANCH_EE to CI_COMMIT_REF_NAME' do
|
||||
expect(subject.variables['BRANCH_EE']).to eq(env['CI_COMMIT_REF_NAME'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "BRANCH_RUNNER" do
|
||||
before do
|
||||
stub_env('CI_PROJECT_PATH', 'gitlab-org/gitlab-runner')
|
||||
end
|
||||
|
||||
context 'when CI_PROJECT_PATH is gitlab-org/gitlab-runner' do
|
||||
it 'sets BRANCH_RUNNER to CI_COMMIT_REF_NAME' do
|
||||
expect(subject.variables['BRANCH_RUNNER']).to eq(env['CI_COMMIT_REF_NAME'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "BRANCH_OMNIBUS" do
|
||||
before do
|
||||
stub_env('CI_PROJECT_PATH', 'gitlab-org/omnibus-gitlab')
|
||||
end
|
||||
|
||||
context 'when CI_PROJECT_PATH is gitlab-org/omnibus-gitlab' do
|
||||
it 'sets BRANCH_OMNIBUS to CI_COMMIT_REF_NAME' do
|
||||
expect(subject.variables['BRANCH_OMNIBUS']).to eq(env['CI_COMMIT_REF_NAME'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "BRANCH_CHARTS" do
|
||||
before do
|
||||
stub_env('CI_PROJECT_PATH', 'gitlab-org/charts/gitlab')
|
||||
end
|
||||
|
||||
context 'when CI_PROJECT_PATH is gitlab-org/charts/gitlab' do
|
||||
it 'sets BRANCH_CHARTS to CI_COMMIT_REF_NAME' do
|
||||
expect(subject.variables['BRANCH_CHARTS']).to eq(env['CI_COMMIT_REF_NAME'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "REVIEW_SLUG" do
|
||||
before do
|
||||
stub_env('CI_PROJECT_PATH', 'gitlab-org/gitlab-foss')
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_IID is set' do
|
||||
it 'sets REVIEW_SLUG' do
|
||||
expect(subject.variables['REVIEW_SLUG']).to eq("-ce-#{env['CI_MERGE_REQUEST_IID']}")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_IID is not set' do
|
||||
before do
|
||||
stub_env('CI_MERGE_REQUEST_IID', nil)
|
||||
end
|
||||
|
||||
it 'sets REVIEW_SLUG' do
|
||||
expect(subject.variables['REVIEW_SLUG']).to eq("-ce-#{env['CI_COMMIT_REF_SLUG']}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.access_token' do
|
||||
context 'when DOCS_PROJECT_API_TOKEN is set' do
|
||||
let(:docs_project_api_token) { 'docs_project_api_token' }
|
||||
|
||||
before do
|
||||
stub_env('DOCS_PROJECT_API_TOKEN', docs_project_api_token)
|
||||
end
|
||||
|
||||
it 'returns the docs-specific access token' do
|
||||
expect(described_class.access_token).to eq(docs_project_api_token)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when DOCS_PROJECT_API_TOKEN is not set' do
|
||||
before do
|
||||
stub_env('DOCS_PROJECT_API_TOKEN', nil)
|
||||
end
|
||||
|
||||
it 'returns the default access token' do
|
||||
expect(described_class.access_token).to eq(Trigger::Base.access_token)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#invoke!' do
|
||||
let(:downstream_project_path) { 'gitlab-org/gitlab-docs' }
|
||||
let(:trigger_token) { 'docs_trigger_token' }
|
||||
let(:ref) { 'main' }
|
||||
|
||||
let(:env) do
|
||||
super().merge(
|
||||
'CI_PROJECT_PATH' => 'gitlab-org/gitlab-foss',
|
||||
'DOCS_PROJECT_API_TOKEN' => nil,
|
||||
'DOCS_TRIGGER_TOKEN' => trigger_token
|
||||
)
|
||||
end
|
||||
|
||||
describe '#downstream_project_path' do
|
||||
context 'when DOCS_PROJECT_PATH is set' do
|
||||
let(:downstream_project_path) { 'docs_project_path' }
|
||||
|
||||
before do
|
||||
stub_env('DOCS_PROJECT_PATH', downstream_project_path)
|
||||
end
|
||||
|
||||
it 'triggers the pipeline on the correct project' do
|
||||
expect_run_trigger_with_params
|
||||
|
||||
subject.invoke!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#ref' do
|
||||
context 'when DOCS_BRANCH is set' do
|
||||
let(:ref) { 'docs_branch' }
|
||||
|
||||
before do
|
||||
stub_env('DOCS_BRANCH', ref)
|
||||
end
|
||||
|
||||
it 'triggers the pipeline on the correct ref' do
|
||||
expect_run_trigger_with_params
|
||||
|
||||
subject.invoke!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Trigger::DatabaseTesting do
|
||||
describe '#variables' do
|
||||
it 'invokes the trigger with expected variables' do
|
||||
expect(subject.variables).to include('TRIGGERED_USER_LOGIN' => env['GITLAB_USER_LOGIN'])
|
||||
end
|
||||
|
||||
describe "GITLAB_COMMIT_SHA" do
|
||||
context 'when CI_MERGE_REQUEST_SOURCE_BRANCH_SHA is set' do
|
||||
before do
|
||||
stub_env('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', 'ci_merge_request_source_branch_sha')
|
||||
end
|
||||
|
||||
it 'sets GITLAB_COMMIT_SHA to ci_merge_request_source_branch_sha' do
|
||||
expect(subject.variables['GITLAB_COMMIT_SHA']).to eq('ci_merge_request_source_branch_sha')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_SOURCE_BRANCH_SHA is set as empty' do
|
||||
before do
|
||||
stub_env('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', '')
|
||||
end
|
||||
|
||||
it 'sets GITLAB_COMMIT_SHA to CI_COMMIT_SHA' do
|
||||
expect(subject.variables['GITLAB_COMMIT_SHA']).to eq(env['CI_COMMIT_SHA'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI_MERGE_REQUEST_SOURCE_BRANCH_SHA is not set' do
|
||||
before do
|
||||
stub_env('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA', nil)
|
||||
end
|
||||
|
||||
it 'sets GITLAB_COMMIT_SHA to CI_COMMIT_SHA' do
|
||||
expect(subject.variables['GITLAB_COMMIT_SHA']).to eq(env['CI_COMMIT_SHA'])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#invoke!' do
|
||||
let(:downstream_project_path) { 'gitlab-com/database-team/gitlab-com-database-testing' }
|
||||
let(:trigger_token) { 'gitlabcom_database_testing_access_token' }
|
||||
let(:api_endpoint) { 'https://ops.gitlab.net/api/v4' }
|
||||
let(:gitlab_client_private_token) { 'gitlabcom_database_testing_access_token' }
|
||||
let(:ref) { 'master' }
|
||||
let(:stubbed_upstream_gitlab_client) { double('upstream_gitlab_api_client') }
|
||||
let(:mr_notes) { [double(body: described_class::IDENTIFIABLE_NOTE_TAG)] }
|
||||
|
||||
let(:env) do
|
||||
super().merge(
|
||||
'GITLABCOM_DATABASE_TESTING_ACCESS_TOKEN' => gitlab_client_private_token,
|
||||
'GITLABCOM_DATABASE_TESTING_TRIGGER_TOKEN' => trigger_token
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
allow(Gitlab).to receive(:client)
|
||||
.with(
|
||||
endpoint: 'https://gitlab.com/api/v4',
|
||||
private_token: env['GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN']
|
||||
)
|
||||
.and_return(stubbed_upstream_gitlab_client)
|
||||
allow(stubbed_upstream_gitlab_client).to receive(:merge_request_notes)
|
||||
.with(
|
||||
env['CI_PROJECT_PATH'],
|
||||
env['CI_MERGE_REQUEST_IID']
|
||||
)
|
||||
.and_return(double(auto_paginate: mr_notes))
|
||||
end
|
||||
|
||||
it 'invokes the trigger with expected variables' do
|
||||
expect_run_trigger_with_params
|
||||
|
||||
subject.invoke!
|
||||
end
|
||||
|
||||
describe '#downstream_project_path' do
|
||||
context 'when GITLABCOM_DATABASE_TESTING_PROJECT_PATH is set' do
|
||||
let(:downstream_project_path) { 'gitlabcom_database_testing_project_path' }
|
||||
|
||||
before do
|
||||
stub_env('GITLABCOM_DATABASE_TESTING_PROJECT_PATH', downstream_project_path)
|
||||
end
|
||||
|
||||
it 'triggers the pipeline on the correct project' do
|
||||
expect_run_trigger_with_params
|
||||
|
||||
subject.invoke!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#ref' do
|
||||
context 'when GITLABCOM_DATABASE_TESTING_TRIGGER_REF is set' do
|
||||
let(:ref) { 'gitlabcom_database_testing_trigger_ref' }
|
||||
|
||||
before do
|
||||
stub_env('GITLABCOM_DATABASE_TESTING_TRIGGER_REF', ref)
|
||||
end
|
||||
|
||||
it 'triggers the pipeline on the correct ref' do
|
||||
expect_run_trigger_with_params
|
||||
|
||||
subject.invoke!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no MR notes with the identifier exist yet' do
|
||||
let(:mr_notes) { [double(body: 'hello world')] }
|
||||
|
||||
it 'posts a new note' do
|
||||
expect_run_trigger_with_params
|
||||
expect(stubbed_upstream_gitlab_client).to receive(:create_merge_request_note)
|
||||
.with(
|
||||
env['CI_PROJECT_PATH'],
|
||||
env['CI_MERGE_REQUEST_IID'],
|
||||
instance_of(String)
|
||||
)
|
||||
.and_return(double(id: 42))
|
||||
|
||||
subject.invoke!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop:enable RSpec/VerifiedDoubles
|
Loading…
Reference in a new issue