summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.markdownlint.json1
-rw-r--r--app/assets/javascripts/static_site_editor/components/saved_changes_message.vue80
-rw-r--r--app/graphql/resolvers/projects/services_resolver.rb39
-rw-r--r--app/graphql/types/project_type.rb6
-rw-r--r--app/graphql/types/projects/service_type.rb29
-rw-r--r--app/graphql/types/projects/service_type_enum.rb13
-rw-r--r--app/graphql/types/projects/services/base_service_type.rb15
-rw-r--r--app/graphql/types/projects/services/jira_service_type.rb18
-rw-r--r--app/models/service.rb65
-rw-r--r--changelogs/unreleased/graphql-expose-project-services.yml5
-rw-r--r--doc/.vale/gitlab/Repetition.yml9
-rw-r--r--doc/administration/auth/ldap-ee.md2
-rw-r--r--doc/administration/auth/ldap-troubleshooting.md2
-rw-r--r--doc/administration/auth/ldap.md2
-rw-r--r--doc/administration/merge_request_diffs.md2
-rw-r--r--doc/administration/scaling/index.md2
-rw-r--r--doc/administration/troubleshooting/debug.md4
-rw-r--r--doc/administration/troubleshooting/postgresql.md2
-rw-r--r--doc/administration/troubleshooting/ssl.md2
-rw-r--r--doc/api/deploy_tokens.md2
-rw-r--r--doc/api/discussions.md2
-rw-r--r--doc/api/epic_links.md2
-rw-r--r--doc/api/graphql/index.md2
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql143
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json540
-rw-r--r--doc/api/graphql/reference/index.md14
-rw-r--r--doc/api/releases/links.md2
-rw-r--r--doc/api/runners.md8
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/index.md2
-rw-r--r--doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md2
-rw-r--r--doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md4
-rw-r--r--doc/ci/pipelines/index.md2
-rw-r--r--doc/ci/pipelines/settings.md2
-rw-r--r--doc/ci/variables/README.md2
-rw-r--r--doc/ci/yaml/README.md10
-rw-r--r--doc/development/api_graphql_styleguide.md8
-rw-r--r--doc/development/architecture.md4
-rw-r--r--doc/development/documentation/workflow.md2
-rw-r--r--doc/development/feature_flags/controls.md3
-rw-r--r--doc/development/gitaly.md2
-rw-r--r--doc/development/integrations/secure.md4
-rw-r--r--doc/development/merge_request_performance_guidelines.md2
-rw-r--r--doc/development/new_fe_guide/tips.md2
-rw-r--r--doc/development/rake_tasks.md2
-rw-r--r--doc/development/testing_guide/end_to_end/best_practices.md5
-rw-r--r--doc/development/testing_guide/end_to_end/quick_start_guide.md2
-rw-r--r--doc/development/uploads.md4
-rw-r--r--doc/install/aws/index.md2
-rw-r--r--doc/integration/elasticsearch.md2
-rw-r--r--doc/integration/gmail_action_buttons_for_gitlab.md12
-rw-r--r--doc/policy/maintenance.md4
-rw-r--r--doc/topics/autodevops/customize.md11
-rw-r--r--doc/topics/autodevops/index.md2
-rw-r--r--doc/topics/git/useful_git_commands.md2
-rw-r--r--doc/user/admin_area/merge_requests_approvals.md16
-rw-r--r--doc/user/application_security/dast/index.md2
-rw-r--r--doc/user/application_security/sast/index.md2
-rw-r--r--doc/user/clusters/management_project.md2
-rw-r--r--doc/user/group/saml_sso/index.md2
-rw-r--r--doc/user/packages/npm_registry/index.md2
-rw-r--r--doc/user/profile/notifications.md2
-rw-r--r--doc/user/project/clusters/add_eks_clusters.md2
-rw-r--r--doc/user/project/highlighting.md2
-rw-r--r--doc/user/project/integrations/prometheus.md2
-rw-r--r--doc/user/project/merge_requests/creating_merge_requests.md2
-rw-r--r--doc/user/project/operations/feature_flags.md8
-rw-r--r--locale/gitlab.pot24
-rw-r--r--spec/frontend/static_site_editor/components/saved_changes_message_spec.js61
-rw-r--r--spec/graphql/resolvers/projects/services_resolver_spec.rb72
-rw-r--r--spec/graphql/types/project_type_spec.rb14
-rw-r--r--spec/graphql/types/projects/base_service_type_spec.rb13
-rw-r--r--spec/graphql/types/projects/jira_service_type_spec.rb13
-rw-r--r--spec/graphql/types/projects/service_type_spec.rb16
-rw-r--r--spec/graphql/types/projects/services_enum_spec.rb15
-rw-r--r--spec/requests/api/graphql/project/base_service_spec.rb47
-rw-r--r--spec/requests/api/graphql/project/jira_service_spec.rb44
-rw-r--r--spec/requests/api/graphql/project_query_spec.rb22
-rw-r--r--spec/support/helpers/graphql_helpers.rb3
-rw-r--r--spec/support/shared_examples/graphql/projects/services_resolver_shared_examples.rb15
-rw-r--r--spec/support/shared_examples/requests/api/graphql/projects/services_shared_examples.rb21
80 files changed, 1414 insertions, 122 deletions
diff --git a/.markdownlint.json b/.markdownlint.json
index 2e12008ef57..056a2fe560b 100644
--- a/.markdownlint.json
+++ b/.markdownlint.json
@@ -102,6 +102,7 @@
"Redis",
"Redmine",
"reCAPTCHA",
+ "Ruby",
"runit",
"Salesforce",
"SAML",
diff --git a/app/assets/javascripts/static_site_editor/components/saved_changes_message.vue b/app/assets/javascripts/static_site_editor/components/saved_changes_message.vue
new file mode 100644
index 00000000000..adcacf8a1b0
--- /dev/null
+++ b/app/assets/javascripts/static_site_editor/components/saved_changes_message.vue
@@ -0,0 +1,80 @@
+<script>
+import { isString } from 'lodash';
+
+import { GlLink, GlNewButton } from '@gitlab/ui';
+
+const validateUrlAndLabel = value => isString(value.label) && isString(value.url);
+
+export default {
+ components: {
+ GlLink,
+ GlNewButton,
+ },
+ props: {
+ branch: {
+ type: Object,
+ required: true,
+ validator: validateUrlAndLabel,
+ },
+ commit: {
+ type: Object,
+ required: true,
+ validator: validateUrlAndLabel,
+ },
+ mergeRequest: {
+ type: Object,
+ required: true,
+ validator: validateUrlAndLabel,
+ },
+ returnUrl: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <div>
+ <h3>{{ s__('StaticSiteEditor|Success!') }}</h3>
+ <p>
+ {{
+ s__(
+ 'StaticSiteEditor|Your changes have been submitted and a merge request has been created. The changes won’t be visible on the site until the merge request has been accepted.',
+ )
+ }}
+ </p>
+ <div>
+ <gl-new-button ref="returnToSiteButton" :href="returnUrl">{{
+ s__('StaticSiteEditor|Return to site')
+ }}</gl-new-button>
+ <gl-new-button ref="mergeRequestButton" :href="mergeRequest.url" variant="info">{{
+ s__('StaticSiteEditor|View merge request')
+ }}</gl-new-button>
+ </div>
+ </div>
+
+ <hr />
+
+ <div>
+ <h4>{{ s__('StaticSiteEditor|Summary of changes') }}</h4>
+ <ul>
+ <li>
+ {{ s__('StaticSiteEditor|A new branch was created:') }}
+ <gl-link ref="branchLink" :href="branch.url">{{ branch.label }}</gl-link>
+ </li>
+ <li>
+ {{ s__('StaticSiteEditor|Your changes were committed to it:') }}
+ <gl-link ref="commitLink" :href="commit.url">{{ commit.label }}</gl-link>
+ </li>
+ <li>
+ {{ s__('StaticSiteEditor|A merge request was created:') }}
+ <gl-link ref="mergeRequestLink" :href="mergeRequest.url">{{
+ mergeRequest.label
+ }}</gl-link>
+ </li>
+ </ul>
+ </div>
+ </div>
+</template>
diff --git a/app/graphql/resolvers/projects/services_resolver.rb b/app/graphql/resolvers/projects/services_resolver.rb
new file mode 100644
index 00000000000..40c64c24513
--- /dev/null
+++ b/app/graphql/resolvers/projects/services_resolver.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Projects
+ class ServicesResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ argument :active,
+ GraphQL::BOOLEAN_TYPE,
+ required: false,
+ description: 'Indicates if the service is active'
+ argument :type,
+ Types::Projects::ServiceTypeEnum,
+ required: false,
+ description: 'Class name of the service'
+
+ alias_method :project, :object
+
+ def resolve(**args)
+ authorize!(project)
+
+ services(args[:active], args[:type])
+ end
+
+ def authorized_resource?(project)
+ Ability.allowed?(context[:current_user], :admin_project, project)
+ end
+
+ private
+
+ def services(active, type)
+ servs = project.services
+ servs = servs.by_active_flag(active) unless active.nil?
+ servs = servs.by_type(type) unless type.blank?
+ servs
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index d82feffe441..3115a53e053 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -199,6 +199,12 @@ module Types
null: true,
description: 'Jira imports into the project',
resolver: Resolvers::Projects::JiraImportsResolver
+
+ field :services,
+ Types::Projects::ServiceType.connection_type,
+ null: true,
+ description: 'Project services',
+ resolver: Resolvers::Projects::ServicesResolver
end
end
diff --git a/app/graphql/types/projects/service_type.rb b/app/graphql/types/projects/service_type.rb
new file mode 100644
index 00000000000..55dd828d4b8
--- /dev/null
+++ b/app/graphql/types/projects/service_type.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Types
+ module Projects
+ module ServiceType
+ include Types::BaseInterface
+ graphql_name 'Service'
+
+ # TODO: Add all the fields that we want to expose for the project services intergrations
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/213088
+ field :type, GraphQL::STRING_TYPE, null: true,
+ description: 'Class name of the service'
+ field :active, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if the service is active'
+
+ definition_methods do
+ def resolve_type(object, context)
+ if object.is_a?(::JiraService)
+ Types::Projects::Services::JiraServiceType
+ else
+ Types::Projects::Services::BaseServiceType
+ end
+ end
+ end
+
+ orphan_types Types::Projects::Services::BaseServiceType, Types::Projects::Services::JiraServiceType
+ end
+ end
+end
diff --git a/app/graphql/types/projects/service_type_enum.rb b/app/graphql/types/projects/service_type_enum.rb
new file mode 100644
index 00000000000..340fdff6b86
--- /dev/null
+++ b/app/graphql/types/projects/service_type_enum.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Types
+ module Projects
+ class ServiceTypeEnum < BaseEnum
+ graphql_name 'ServiceType'
+
+ ::Service.services_types.each do |service_type|
+ value service_type.underscore.upcase, value: service_type
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/projects/services/base_service_type.rb b/app/graphql/types/projects/services/base_service_type.rb
new file mode 100644
index 00000000000..5341ae2a864
--- /dev/null
+++ b/app/graphql/types/projects/services/base_service_type.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Types
+ module Projects
+ module Services
+ class BaseServiceType < BaseObject
+ graphql_name 'BaseService'
+
+ implements(Types::Projects::ServiceType)
+
+ authorize :admin_project
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/projects/services/jira_service_type.rb b/app/graphql/types/projects/services/jira_service_type.rb
new file mode 100644
index 00000000000..4fd9e61f5a4
--- /dev/null
+++ b/app/graphql/types/projects/services/jira_service_type.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Types
+ module Projects
+ module Services
+ class JiraServiceType < BaseObject
+ graphql_name 'JiraService'
+
+ implements(Types::Projects::ServiceType)
+
+ authorize :admin_project
+ # This is a placeholder for now for the actuall implementation of the JiraServiceType
+ # Here we will want to expose a field with jira_projects fetched through Jira Rest API
+ # MR implementing it https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28190
+ end
+ end
+ end
+end
diff --git a/app/models/service.rb b/app/models/service.rb
index 017c15468a2..543869c71d6 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -8,6 +8,17 @@ class Service < ApplicationRecord
include ProjectServicesLoggable
include DataFields
+ SERVICE_NAMES = %w[
+ alerts asana assembla bamboo bugzilla buildkite campfire custom_issue_tracker discord
+ drone_ci emails_on_push external_wiki flowdock hangouts_chat hipchat irker jira
+ mattermost mattermost_slash_commands microsoft_teams packagist pipelines_email
+ pivotaltracker prometheus pushover redmine slack slack_slash_commands teamcity unify_circuit youtrack
+ ].freeze
+
+ DEV_SERVICE_NAMES = %w[
+ mock_ci mock_deployment mock_monitoring
+ ].freeze
+
serialize :properties, JSON # rubocop:disable Cop/ActiveRecordSerialize
default_value_for :active, false
@@ -46,6 +57,7 @@ class Service < ApplicationRecord
scope :active, -> { where(active: true) }
scope :without_defaults, -> { where(default: false) }
scope :by_type, -> (type) { where(type: type) }
+ scope :by_active_flag, -> (flag) { where(active: flag) }
scope :templates, -> { where(template: true, type: available_services_types) }
scope :instances, -> { where(instance: true, type: available_services_types) }
@@ -295,51 +307,30 @@ class Service < ApplicationRecord
end
def self.available_services_names
- service_names = %w[
- alerts
- asana
- assembla
- bamboo
- bugzilla
- buildkite
- campfire
- custom_issue_tracker
- discord
- drone_ci
- emails_on_push
- external_wiki
- flowdock
- hangouts_chat
- hipchat
- irker
- jira
- mattermost
- mattermost_slash_commands
- microsoft_teams
- packagist
- pipelines_email
- pivotaltracker
- prometheus
- pushover
- redmine
- slack
- slack_slash_commands
- teamcity
- unify_circuit
- youtrack
- ]
-
- if Rails.env.development?
- service_names += %w[mock_ci mock_deployment mock_monitoring]
- end
+ service_names = services_names
+ service_names += dev_services_names
service_names.sort_by(&:downcase)
end
+ def self.services_names
+ SERVICE_NAMES
+ end
+
+ def self.dev_services_names
+ return [] unless Rails.env.development?
+
+ DEV_SERVICE_NAMES
+ end
+
def self.available_services_types
available_services_names.map { |service_name| "#{service_name}_service".camelize }
end
+ def self.services_types
+ services_names.map { |service_name| "#{service_name}_service".camelize }
+ end
+
def self.build_from_template(project_id, template)
service = template.dup
diff --git a/changelogs/unreleased/graphql-expose-project-services.yml b/changelogs/unreleased/graphql-expose-project-services.yml
new file mode 100644
index 00000000000..43edd33decf
--- /dev/null
+++ b/changelogs/unreleased/graphql-expose-project-services.yml
@@ -0,0 +1,5 @@
+---
+title: Expose basic project services attributes through GraphQL
+merge_request: 28234
+author:
+type: added
diff --git a/doc/.vale/gitlab/Repetition.yml b/doc/.vale/gitlab/Repetition.yml
new file mode 100644
index 00000000000..8477a4feb58
--- /dev/null
+++ b/doc/.vale/gitlab/Repetition.yml
@@ -0,0 +1,9 @@
+# Checks for duplicate words, like `the the` or `and and`.
+#
+# For a list of all options, see https://errata-ai.github.io/vale/styles/
+extends: repetition
+message: '"%s" is repeated.'
+level: error
+alpha: true
+tokens:
+ - '[^\s]+'
diff --git a/doc/administration/auth/ldap-ee.md b/doc/administration/auth/ldap-ee.md
index a87118a800a..3bc30c4c01c 100644
--- a/doc/administration/auth/ldap-ee.md
+++ b/doc/administration/auth/ldap-ee.md
@@ -4,7 +4,7 @@ type: reference
# LDAP Additions in GitLab EE **(STARTER ONLY)**
-This section documents LDAP features specific to to GitLab Enterprise Edition
+This section documents LDAP features specific to GitLab Enterprise Edition
[Starter](https://about.gitlab.com/pricing/#self-managed) and above.
For documentation relevant to both Community Edition and Enterprise Edition,
diff --git a/doc/administration/auth/ldap-troubleshooting.md b/doc/administration/auth/ldap-troubleshooting.md
index b852140e80a..612f782e841 100644
--- a/doc/administration/auth/ldap-troubleshooting.md
+++ b/doc/administration/auth/ldap-troubleshooting.md
@@ -227,7 +227,7 @@ uid: John
There's a lot here, so let's go over what could be helpful when debugging.
-First, GitLab will look for all users that have have previously
+First, GitLab will look for all users that have previously
logged in with LDAP and iterate on them. Each user's sync will start with
the following line that contains the user's username and email, as they
exist in GitLab now:
diff --git a/doc/administration/auth/ldap.md b/doc/administration/auth/ldap.md
index 12a42ec0a1e..1e91b539db5 100644
--- a/doc/administration/auth/ldap.md
+++ b/doc/administration/auth/ldap.md
@@ -498,7 +498,7 @@ the configuration option `lowercase_usernames`. By default, this configuration o
## Disable LDAP web sign in
-It can be be useful to prevent using LDAP credentials through the web UI when
+It can be useful to prevent using LDAP credentials through the web UI when
an alternative such as SAML is preferred. This allows LDAP to be used for group
sync, while also allowing your SAML identity provider to handle additional
checks like custom 2FA.
diff --git a/doc/administration/merge_request_diffs.md b/doc/administration/merge_request_diffs.md
index ca09171e5ff..fd1a425d6b1 100644
--- a/doc/administration/merge_request_diffs.md
+++ b/doc/administration/merge_request_diffs.md
@@ -25,7 +25,7 @@ To enable external storage of merge request diffs, follow the instructions below
gitlab_rails['external_diffs_enabled'] = true
```
-1. _The external diffs will be stored in in
+1. _The external diffs will be stored in
`/var/opt/gitlab/gitlab-rails/shared/external-diffs`._ To change the path,
for example, to `/mnt/storage/external-diffs`, edit `/etc/gitlab/gitlab.rb`
and add the following line:
diff --git a/doc/administration/scaling/index.md b/doc/administration/scaling/index.md
index 99e8ca9a65f..1ef9eca2497 100644
--- a/doc/administration/scaling/index.md
+++ b/doc/administration/scaling/index.md
@@ -21,7 +21,7 @@ part of a source installation and their configuration instructions for scaling.
|-----------|-------------|----------------------------|
| [PostgreSQL](../../development/architecture.md#postgresql) | Database | [PostgreSQL configuration](https://docs.gitlab.com/omnibus/settings/database.html) |
| [Redis](../../development/architecture.md#redis) | Key/value store for fast data lookup and caching | [Redis configuration](../high_availability/redis.md) |
-| [GitLab application services](../../development/architecture.md#unicorn) | Unicorn/Puma, Workhorse, GitLab Shell - serves front-end requests requests (UI, API, Git over HTTP/SSH) | [GitLab app scaling configuration](../high_availability/gitlab.md) |
+| [GitLab application services](../../development/architecture.md#unicorn) | Unicorn/Puma, Workhorse, GitLab Shell - serves front-end requests (UI, API, Git over HTTP/SSH) | [GitLab app scaling configuration](../high_availability/gitlab.md) |
| [PgBouncer](../../development/architecture.md#pgbouncer) | Database connection pooler | [PgBouncer configuration](../high_availability/pgbouncer.md#running-pgbouncer-as-part-of-a-non-ha-gitlab-installation) **(PREMIUM ONLY)** |
| [Sidekiq](../../development/architecture.md#sidekiq) | Asynchronous/background jobs | [Sidekiq configuration](../high_availability/sidekiq.md) |
| [Gitaly](../../development/architecture.md#gitaly) | Provides access to Git repositories | [Gitaly configuration](../gitaly/index.md#running-gitaly-on-its-own-server) |
diff --git a/doc/administration/troubleshooting/debug.md b/doc/administration/troubleshooting/debug.md
index 295dab2be38..d0c1f3fa0ff 100644
--- a/doc/administration/troubleshooting/debug.md
+++ b/doc/administration/troubleshooting/debug.md
@@ -241,7 +241,7 @@ separate Rails process to debug the issue:
app.get 'https://gitlab.com/gitlab-org/gitlab-foss/issues/1?private_token=123456'
```
-1. In a new window, run `top`. It should show this ruby process using 100% CPU. Write down the PID.
+1. In a new window, run `top`. It should show this Ruby process using 100% CPU. Write down the PID.
1. Follow step 2 from the previous section on using gdb.
### GitLab: API is not accessible
@@ -275,4 +275,4 @@ The output in `/tmp/unicorn.txt` may help diagnose the root cause.
## More information
- [Debugging Stuck Ruby Processes](https://blog.newrelic.com/engineering/debugging-stuck-ruby-processes-what-to-do-before-you-kill-9/)
-- [Cheatsheet of using gdb and ruby processes](gdb-stuck-ruby.txt)
+- [Cheatsheet of using gdb and Ruby processes](gdb-stuck-ruby.txt)
diff --git a/doc/administration/troubleshooting/postgresql.md b/doc/administration/troubleshooting/postgresql.md
index 966db356849..8e7727ee214 100644
--- a/doc/administration/troubleshooting/postgresql.md
+++ b/doc/administration/troubleshooting/postgresql.md
@@ -111,7 +111,7 @@ statement_timeout = 15s
idle_in_transaction_session_timeout = 60s
```
-Quoting from from issue [#1](https://gitlab.com/gitlab-org/gitlab/issues/30528):
+Quoting from issue [#1](https://gitlab.com/gitlab-org/gitlab/issues/30528):
> "If a deadlock is hit, and we resolve it through aborting the transaction after a short period, then the retry mechanisms we already have will make the deadlocked piece of work try again, and it's unlikely we'll deadlock multiple times in a row."
diff --git a/doc/administration/troubleshooting/ssl.md b/doc/administration/troubleshooting/ssl.md
index b66b6e8c90a..f230f047ded 100644
--- a/doc/administration/troubleshooting/ssl.md
+++ b/doc/administration/troubleshooting/ssl.md
@@ -50,7 +50,7 @@ If you have the problems listed above, add your certificate to `/etc/gitlab/trus
Besides getting the errors mentioned in
[Using an internal CA certificate with GitLab](ssl.md#using-an-internal-ca-certificate-with-gitlab),
-your CI pipelines may stuck stuck in `Pending` status. In the runner logs you may see the below error:
+your CI pipelines may get stuck in `Pending` status. In the runner logs you may see the below error:
```shell
Dec 6 02:43:17 runner-host01 gitlab-runner[15131]: #033[0;33mWARNING: Checking for jobs... failed
diff --git a/doc/api/deploy_tokens.md b/doc/api/deploy_tokens.md
index 4d62fc857ba..4663159f1eb 100644
--- a/doc/api/deploy_tokens.md
+++ b/doc/api/deploy_tokens.md
@@ -138,7 +138,7 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
These endpoints require group maintainer access or higher.
-### List group deploy deploy tokens
+### List group deploy tokens
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/21811) in GitLab 12.9.
diff --git a/doc/api/discussions.md b/doc/api/discussions.md
index 936fcae0b72..f1e8965b336 100644
--- a/doc/api/discussions.md
+++ b/doc/api/discussions.md
@@ -552,7 +552,7 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab
### Create new epic thread
Creates a new thread to a single group epic. This is similar to creating
-a note but but other comments (replies) can be added to it later.
+a note but other comments (replies) can be added to it later.
```plaintext
POST /groups/:id/epics/:epic_id/discussions
diff --git a/doc/api/epic_links.md b/doc/api/epic_links.md
index 5df91e106eb..36503942729 100644
--- a/doc/api/epic_links.md
+++ b/doc/api/epic_links.md
@@ -120,7 +120,7 @@ Example response:
## Create and assign a child epic
-Creates a a new epic and associates it with provided parent epic. The response is LinkedEpic object.
+Creates a new epic and associates it with provided parent epic. The response is LinkedEpic object.
```plaintext
POST /groups/:id/epics/:epic_iid/epics
diff --git a/doc/api/graphql/index.md b/doc/api/graphql/index.md
index dc691185d28..044c3500bf4 100644
--- a/doc/api/graphql/index.md
+++ b/doc/api/graphql/index.md
@@ -73,7 +73,7 @@ Root-level queries are defined in
GitLab supports batching queries into a single request using
[apollo-link-batch-http](https://www.apollographql.com/docs/link/links/batch-http/). More
information about multiplexed queries is also available for
-[graphql-ruby](https://graphql-ruby.org/queries/multiplex.html) the
+[GraphQL Ruby](https://graphql-ruby.org/queries/multiplex.html), the
library GitLab uses on the backend.
## Reference
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 2696c7355bc..7e863490369 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -138,6 +138,18 @@ type AwardEmoji {
user: User!
}
+type BaseService implements Service {
+ """
+ Indicates if the service is active
+ """
+ active: Boolean
+
+ """
+ Class name of the service
+ """
+ type: String
+}
+
type Blob implements Entry {
"""
Flat path of the entry
@@ -4246,6 +4258,18 @@ type JiraImportStartPayload {
jiraImport: JiraImport
}
+type JiraService implements Service {
+ """
+ Indicates if the service is active
+ """
+ active: Boolean
+
+ """
+ Class name of the service
+ """
+ type: String
+}
+
type Label {
"""
Background color of the label
@@ -6411,6 +6435,41 @@ type Project {
serviceDeskEnabled: Boolean
"""
+ Project services
+ """
+ services(
+ """
+ Indicates if the service is active
+ """
+ active: Boolean
+
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+
+ """
+ Class name of the service
+ """
+ type: ServiceType
+ ): ServiceConnection
+
+ """
Indicates if Shared Runners are enabled for the project
"""
sharedRunnersEnabled: Boolean
@@ -7637,6 +7696,90 @@ type SentryErrorTags {
logger: String
}
+interface Service {
+ """
+ Indicates if the service is active
+ """
+ active: Boolean
+
+ """
+ Class name of the service
+ """
+ type: String
+}
+
+"""
+The connection type for Service.
+"""
+type ServiceConnection {
+ """
+ A list of edges.
+ """
+ edges: [ServiceEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [Service]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type ServiceEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: Service
+}
+
+enum ServiceType {
+ ALERTS_SERVICE
+ ASANA_SERVICE
+ ASSEMBLA_SERVICE
+ BAMBOO_SERVICE
+ BUGZILLA_SERVICE
+ BUILDKITE_SERVICE
+ CAMPFIRE_SERVICE
+ CUSTOM_ISSUE_TRACKER_SERVICE
+ DISCORD_SERVICE
+ DRONE_CI_SERVICE
+ EMAILS_ON_PUSH_SERVICE
+ EXTERNAL_WIKI_SERVICE
+ FLOWDOCK_SERVICE
+ GITHUB_SERVICE
+ HANGOUTS_CHAT_SERVICE
+ HIPCHAT_SERVICE
+ IRKER_SERVICE
+ JENKINS_DEPRECATED_SERVICE
+ JENKINS_SERVICE
+ JIRA_SERVICE
+ MATTERMOST_SERVICE
+ MATTERMOST_SLASH_COMMANDS_SERVICE
+ MICROSOFT_TEAMS_SERVICE
+ PACKAGIST_SERVICE
+ PIPELINES_EMAIL_SERVICE
+ PIVOTALTRACKER_SERVICE
+ PROMETHEUS_SERVICE
+ PUSHOVER_SERVICE
+ REDMINE_SERVICE
+ SLACK_SERVICE
+ SLACK_SLASH_COMMANDS_SERVICE
+ TEAMCITY_SERVICE
+ UNIFY_CIRCUIT_SERVICE
+ YOUTRACK_SERVICE
+}
+
"""
Represents a snippet entry
"""
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index 66f4ce0940f..813ab39795a 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -410,6 +410,51 @@
},
{
"kind": "OBJECT",
+ "name": "BaseService",
+ "description": null,
+ "fields": [
+ {
+ "name": "active",
+ "description": "Indicates if the service is active",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "type",
+ "description": "Class name of the service",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+ {
+ "kind": "INTERFACE",
+ "name": "Service",
+ "ofType": null
+ }
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
"name": "Blob",
"description": null,
"fields": [
@@ -12063,6 +12108,51 @@
},
{
"kind": "OBJECT",
+ "name": "JiraService",
+ "description": null,
+ "fields": [
+ {
+ "name": "active",
+ "description": "Indicates if the service is active",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "type",
+ "description": "Class name of the service",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+ {
+ "kind": "INTERFACE",
+ "name": "Service",
+ "ofType": null
+ }
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
"name": "Label",
"description": null,
"fields": [
@@ -19142,6 +19232,79 @@
"deprecationReason": null
},
{
+ "name": "services",
+ "description": "Project services",
+ "args": [
+ {
+ "name": "active",
+ "description": "Indicates if the service is active",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "type",
+ "description": "Class name of the service",
+ "type": {
+ "kind": "ENUM",
+ "name": "ServiceType",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "ServiceConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "sharedRunnersEnabled",
"description": "Indicates if Shared Runners are enabled for the project",
"args": [
@@ -23019,6 +23182,383 @@
"possibleTypes": null
},
{
+ "kind": "INTERFACE",
+ "name": "Service",
+ "description": null,
+ "fields": [
+ {
+ "name": "active",
+ "description": "Indicates if the service is active",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "type",
+ "description": "Class name of the service",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": [
+ {
+ "kind": "OBJECT",
+ "name": "BaseService",
+ "ofType": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "JiraService",
+ "ofType": null
+ }
+ ]
+ },
+ {
+ "kind": "OBJECT",
+ "name": "ServiceConnection",
+ "description": "The connection type for Service.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "ServiceEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "INTERFACE",
+ "name": "Service",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "ServiceEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "INTERFACE",
+ "name": "Service",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "ServiceType",
+ "description": null,
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "ALERTS_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "ASANA_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "ASSEMBLA_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "BAMBOO_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "BUGZILLA_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "BUILDKITE_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "CAMPFIRE_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "CUSTOM_ISSUE_TRACKER_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "DISCORD_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "DRONE_CI_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "EMAILS_ON_PUSH_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "EXTERNAL_WIKI_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "FLOWDOCK_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "HANGOUTS_CHAT_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "HIPCHAT_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "IRKER_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "JIRA_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "MATTERMOST_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "MATTERMOST_SLASH_COMMANDS_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "MICROSOFT_TEAMS_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "PACKAGIST_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "PIPELINES_EMAIL_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "PIVOTALTRACKER_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "PROMETHEUS_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "PUSHOVER_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "REDMINE_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "SLACK_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "SLACK_SLASH_COMMANDS_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "TEAMCITY_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "UNIFY_CIRCUIT_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "YOUTRACK_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "GITHUB_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "JENKINS_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "JENKINS_DEPRECATED_SERVICE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "Snippet",
"description": "Represents a snippet entry",
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index d1ddcb6435b..dbe98639d23 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -49,6 +49,13 @@ An emoji awarded by a user.
| `unicodeVersion` | String! | The unicode version for this emoji |
| `user` | User! | The user who awarded the emoji |
+## BaseService
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `active` | Boolean | Indicates if the service is active |
+| `type` | String | Class name of the service |
+
## Blob
| Name | Type | Description |
@@ -624,6 +631,13 @@ Autogenerated return type of JiraImportStart
| `errors` | String! => Array | Reasons why the mutation failed. |
| `jiraImport` | JiraImport | The Jira import data after mutation |
+## JiraService
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `active` | Boolean | Indicates if the service is active |
+| `type` | String | Class name of the service |
+
## Label
| Name | Type | Description |
diff --git a/doc/api/releases/links.md b/doc/api/releases/links.md
index ed428b0fe75..bf882ef35c0 100644
--- a/doc/api/releases/links.md
+++ b/doc/api/releases/links.md
@@ -3,7 +3,7 @@
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/41766) in GitLab 11.7.
Using this API you can manipulate GitLab's [Release](../../user/project/releases/index.md) links. For manipulating other Release assets, see [Release API](index.md).
-GitLab supports links links to `http`, `https`, and `ftp` assets.
+GitLab supports links to `http`, `https`, and `ftp` assets.
## Get links
diff --git a/doc/api/runners.md b/doc/api/runners.md
index c17069b4474..523f0363cee 100644
--- a/doc/api/runners.md
+++ b/doc/api/runners.md
@@ -42,7 +42,7 @@ GET /runners?tag_list=tag1,tag2
| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of specific runners to show, one of: `active`, `paused`, `online`, `offline`; showing all runners if none provided |
| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` |
| `status` | string | no | The status of runners to show, one of: `active`, `paused`, `online`, `offline` |
-| `tag_list` | string array | no | List of of the runner's tags |
+| `tag_list` | string array | no | List of the runner's tags |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners"
@@ -93,7 +93,7 @@ GET /runners/all?tag_list=tag1,tag2
| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of runners to show, one of: `specific`, `shared`, `active`, `paused`, `online`, `offline`; showing all runners if none provided |
| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` |
| `status` | string | no | The status of runners to show, one of: `active`, `paused`, `online`, `offline` |
-| `tag_list` | string array | no | List of of the runner's tags |
+| `tag_list` | string array | no | List of the runner's tags |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners/all"
@@ -385,7 +385,7 @@ GET /projects/:id/runners?tag_list=tag1,tag2
| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of specific runners to show, one of: `active`, `paused`, `online`, `offline`; showing all runners if none provided |
| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` |
| `status` | string | no | The status of runners to show, one of: `active`, `paused`, `online`, `offline` |
-| `tag_list` | string array | no | List of of the runner's tags |
+| `tag_list` | string array | no | List of the runner's tags |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/9/runners"
@@ -486,7 +486,7 @@ GET /groups/:id/runners?tag_list=tag1,tag2
| `id` | integer | yes | The ID of the group owned by the authenticated user |
| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` |
| `status` | string | no | The status of runners to show, one of: `active`, `paused`, `online`, `offline` |
-| `tag_list` | string array | no | List of of the runner's tags |
+| `tag_list` | string array | no | List of the runner's tags |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/9/runners"
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
index c8f5d48c4ef..07b054dd2cb 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
@@ -277,7 +277,7 @@ The `releases` directory will hold all our deployments:
...
```
-While our project grows, its Git history will be very very long over time.
+While our project grows, its Git history will be very long over time.
Since we are creating a directory per release, it might not be necessary to have the history of the project downloaded for each release.
The `--depth 1` option is a great solution which saves systems time and disk space as well.
diff --git a/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md b/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md
index 0ab5bf1e3bb..e480f4565ce 100644
--- a/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md
+++ b/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md
@@ -77,6 +77,6 @@ gitlab-runner register \
--docker-services latest
```
-With the command above, you create a Runner that uses the [ruby:2.6](https://hub.docker.com/_/ruby) image and uses a [PostgreSQL](https://hub.docker.com/_/postgres) database.
+With the command above, you create a Runner that uses the [`ruby:2.6`](https://hub.docker.com/_/ruby) image and uses a [PostgreSQL](https://hub.docker.com/_/postgres) database.
To access the PostgreSQL database, connect to `host: postgres` as user `postgres` with no password.
diff --git a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md
index 27e30dd3a10..6d92c86c819 100644
--- a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md
+++ b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md
@@ -12,7 +12,7 @@ last_updated: 2019-03-06
[Phoenix](https://www.phoenixframework.org/) is a web development framework written in [Elixir](https://elixir-lang.org), which is a
functional language designed for productivity and maintainability that runs on the
-[Erlang VM](https://www.erlang.org). Erlang VM is really really fast and can handle very large numbers of
+[Erlang VM](https://www.erlang.org). Erlang VM is really fast and can handle very large numbers of
simultaneous users.
That's why we're hearing so much about Phoenix today.
@@ -389,7 +389,7 @@ source project being watched and contributed by the community, it is really impo
code permanently working. GitLab CI/CD is a time saving powerful tool to help us maintain our code
organized and working.
-As we could see in this post, GitLab CI/CD is really really easy to configure and use. We have [many
+As we could see in this post, GitLab CI/CD is really easy to configure and use. We have [many
other reasons](https://about.gitlab.com/blog/2015/02/03/7-reasons-why-you-should-be-using-ci/) to keep
using GitLab CI/CD. The benefits to our teams will be huge!
diff --git a/doc/ci/pipelines/index.md b/doc/ci/pipelines/index.md
index 18f5c5f6827..5ce4e1649bc 100644
--- a/doc/ci/pipelines/index.md
+++ b/doc/ci/pipelines/index.md
@@ -475,7 +475,7 @@ to an updated status.
This functionality is only available:
- For users with at least Developer access.
-- If the the stage contains [manual actions](#manual-actions-from-pipeline-graphs).
+- If the stage contains [manual actions](#manual-actions-from-pipeline-graphs).
### Deleting a single pipeline
diff --git a/doc/ci/pipelines/settings.md b/doc/ci/pipelines/settings.md
index b1c5ee6e24f..bddf64f397e 100644
--- a/doc/ci/pipelines/settings.md
+++ b/doc/ci/pipelines/settings.md
@@ -117,7 +117,7 @@ job log using a regular expression. In the pipelines settings, search for the
![Pipelines settings test coverage](img/pipelines_settings_test_coverage.png)
-Leave blank if you want to disable it or enter a ruby regular expression. You
+Leave blank if you want to disable it or enter a Ruby regular expression. You
can use <https://rubular.com> to test your regex.
If the pipeline succeeds, the coverage is shown in the merge request widget and
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index afa2e247679..d363a4387d9 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -429,7 +429,7 @@ Once you set them, they will be available for all subsequent pipelines.
You can limit the environment scope of a variable by
[defining which environments](../environments.md) it can be available for.
-To learn more about about scoping environments, see [Scoping environments with specs](../environments.md#scoping-environments-with-specs).
+To learn more about scoping environments, see [Scoping environments with specs](../environments.md#scoping-environments-with-specs).
### Deployment environment variables
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index b72cf25282b..558ae5e20d3 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -318,25 +318,25 @@ For:
An [extended docker configuration option](../docker/using_docker_images.md#extended-docker-configuration-options).
-For more information, see see [Available settings for `services`](../docker/using_docker_images.md#available-settings-for-services).
+For more information, see [Available settings for `services`](../docker/using_docker_images.md#available-settings-for-services).
#### `services:alias`
An [extended docker configuration option](../docker/using_docker_images.md#extended-docker-configuration-options).
-For more information, see see [Available settings for `services`](../docker/using_docker_images.md#available-settings-for-services).
+For more information, see [Available settings for `services`](../docker/using_docker_images.md#available-settings-for-services).
#### `services:entrypoint`
An [extended docker configuration option](../docker/using_docker_images.md#extended-docker-configuration-options).
-For more information, see see [Available settings for `services`](../docker/using_docker_images.md#available-settings-for-services).
+For more information, see [Available settings for `services`](../docker/using_docker_images.md#available-settings-for-services).
#### `services:command`
An [extended docker configuration option](../docker/using_docker_images.md#extended-docker-configuration-options).
-For more information, see see [Available settings for `services`](../docker/using_docker_images.md#available-settings-for-services).
+For more information, see [Available settings for `services`](../docker/using_docker_images.md#available-settings-for-services).
### `before_script` and `after_script`
@@ -1630,7 +1630,7 @@ The `stop_review_app` job is **required** to have the following keywords defined
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/20956) in GitLab 12.8.
The `auto_stop_in` keyword is for specifying life period of the environment,
-that when expired, GitLab GitLab automatically stops them.
+that when expired, GitLab automatically stops them.
For example,
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index 6d224db1a02..ea58b71a804 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -4,7 +4,7 @@ This document outlines the styleguide for GitLab's [GraphQL API](../api/graphql/
## How GitLab implements GraphQL
-We use the [graphql-ruby gem](https://graphql-ruby.org/) written by [Robert Mosolgo](https://github.com/rmosolgo/).
+We use the [GraphQL Ruby gem](https://graphql-ruby.org/) written by [Robert Mosolgo](https://github.com/rmosolgo/).
All GraphQL queries are directed to a single endpoint
([`app/controllers/graphql_controller.rb#execute`](https://gitlab.com/gitlab-org/gitlab/blob/master/app%2Fcontrollers%2Fgraphql_controller.rb)),
@@ -84,7 +84,7 @@ the context.
### Nullable fields
-GraphQL allows fields to be be "nullable" or "non-nullable". The former means
+GraphQL allows fields to be "nullable" or "non-nullable". The former means
that `null` may be returned instead of a value of the specified type. **In
general**, you should prefer using nullable fields to non-nullable ones, for
the following reasons:
@@ -865,7 +865,7 @@ the analyzer, and the final value is also available to you.
[Multiplex queries](https://graphql-ruby.org/queries/multiplex.html) enable
multiple queries to be sent in a single request. This reduces the number of requests sent to the server.
-(there are custom Multiplex Query Analyzers and Multiplex Instrumentation provided by graphql-ruby).
+(there are custom Multiplex Query Analyzers and Multiplex Instrumentation provided by GraphQL Ruby).
### Query limits
@@ -888,7 +888,7 @@ end
```
More about complexity:
-[graphql-ruby docs](https://graphql-ruby.org/queries/complexity_and_depth.html)
+[GraphQL Ruby documentation](https://graphql-ruby.org/queries/complexity_and_depth.html).
## Documentation and Schema
diff --git a/doc/development/architecture.md b/doc/development/architecture.md
index b5caa1d223d..436cb43199e 100644
--- a/doc/development/architecture.md
+++ b/doc/development/architecture.md
@@ -775,7 +775,7 @@ When referring to `~git` in the pictures it means the home directory of the Git
GitLab is primarily installed within the `/home/git` user home directory as `git` user. Within the home directory is where the gitlabhq server software resides as well as the repositories (though the repository location is configurable).
-The bare repositories are located in `/home/git/repositories`. GitLab is a ruby on rails application so the particulars of the inner workings can be learned by studying how a ruby on rails application works.
+The bare repositories are located in `/home/git/repositories`. GitLab is a Ruby on rails application so the particulars of the inner workings can be learned by studying how a Ruby on rails application works.
To serve repositories over SSH there's an add-on application called GitLab Shell which is installed in `/home/git/gitlab-shell`.
@@ -794,7 +794,7 @@ GitLab has several components to operate. It requires a persistent database
Unicorn. All these components should run as different system users to GitLab
(e.g., `postgres`, `redis` and `www-data`, instead of `git`).
-As the `git` user it starts Sidekiq and Unicorn (a simple ruby HTTP server
+As the `git` user it starts Sidekiq and Unicorn (a simple Ruby HTTP server
running on port `8080` by default). Under the GitLab user there are normally 4
processes: `unicorn_rails master` (1 process), `unicorn_rails worker`
(2 processes), `sidekiq` (1 process).
diff --git a/doc/development/documentation/workflow.md b/doc/development/documentation/workflow.md
index aaf0f218387..01f528dcfa4 100644
--- a/doc/development/documentation/workflow.md
+++ b/doc/development/documentation/workflow.md
@@ -422,7 +422,7 @@ Request help from the Technical Writing team if you:
To request help:
-1. Locate the the Technical Writer for the relevant
+1. Locate the Technical Writer for the relevant
[DevOps stage group](https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments).
1. Either:
- If urgent help is required, directly assign the Technical Writer in the issue or in the merge request.
diff --git a/doc/development/feature_flags/controls.md b/doc/development/feature_flags/controls.md
index 21d6d48d446..fa9942e8d81 100644
--- a/doc/development/feature_flags/controls.md
+++ b/doc/development/feature_flags/controls.md
@@ -98,7 +98,8 @@ Slack:
This will enable the feature for GitLab.com, with `new_navigation_bar` being the
name of the feature.
-This command does *not* enable the feature for 25% of the total users. Instead, when the feature is checked with `enabled?`, it will return `true` 25% of the time.
+This command does *not* enable the feature for 25% of the total users.
+Instead, when the feature is checked with `enabled?`, it will return `true` 25% of the time.
If you are not certain what percentages to use, simply use the following steps:
diff --git a/doc/development/gitaly.md b/doc/development/gitaly.md
index b8b33de8083..43e4d4d0e72 100644
--- a/doc/development/gitaly.md
+++ b/doc/development/gitaly.md
@@ -58,7 +58,7 @@ of Gitaly and `gitaly-proto` during testing and development.
- See [below](#running-tests-with-a-locally-modified-version-of-gitaly) for instructions on running GitLab CE tests with a modified version of Gitaly.
- In GDK run `gdk install` and restart `gdk run` (or `gdk run app`) to use a locally modified Gitaly version for development
-### Gitaly-ruby
+### `gitaly-ruby`
It is possible to implement and test RPC's in Gitaly using Ruby code,
in
diff --git a/doc/development/integrations/secure.md b/doc/development/integrations/secure.md
index 30d6c2ae754..69128cfb625 100644
--- a/doc/development/integrations/secure.md
+++ b/doc/development/integrations/secure.md
@@ -37,7 +37,7 @@ For instance, it is common practice to use `before_script` to install system lib
a particular project needs before performing SAST or Dependency Scanning.
Similarly, [`after_script`](../../ci/yaml/README.md#before_script-and-after_script)
-should not not be used in the job definition, because it may be overridden by users.
+should not be used in the job definition, because it may be overridden by users.
### Stage
@@ -403,7 +403,7 @@ It may also have an `end_line`, a `class`, and a `method`.
For instance, here is the `location` object for a security flaw found
at line `41` of `src/main/java/com/gitlab/example/App.java`,
-in the the `generateSecretToken` method of the `com.gitlab.security_products.tests.App` Java class:
+in the `generateSecretToken` method of the `com.gitlab.security_products.tests.App` Java class:
```json
{
diff --git a/doc/development/merge_request_performance_guidelines.md b/doc/development/merge_request_performance_guidelines.md
index a285d30d7a5..4a9b5d26aef 100644
--- a/doc/development/merge_request_performance_guidelines.md
+++ b/doc/development/merge_request_performance_guidelines.md
@@ -375,7 +375,7 @@ Examples:
In such cases it's rather expected that this is either misuse
or abuse of the feature. Lack of the upper limit can result
in service degradation as the system will try to process all schedules
- assigned the the project.
+ assigned the project.
1. GitLab CI/CD includes: We started with the limit of maximum of 50 nested includes.
We understood that performance of the feature was acceptable at that level.
diff --git a/doc/development/new_fe_guide/tips.md b/doc/development/new_fe_guide/tips.md
index 2e2f5e8f47d..13222e0cc9b 100644
--- a/doc/development/new_fe_guide/tips.md
+++ b/doc/development/new_fe_guide/tips.md
@@ -16,7 +16,7 @@ Your feature flag can now be:
- [Made available to the frontend](../feature_flags/development.md#frontend) via the `gon`
- Queried in [tests](../feature_flags/development.md#specs)
-- Queried in HAML templates and ruby files via the `Feature.enabled?(:my_shiny_new_feature_flag)` method
+- Queried in HAML templates and Ruby files via the `Feature.enabled?(:my_shiny_new_feature_flag)` method
### More on feature flags
diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md
index 3bc638ca6f2..600afcff1b0 100644
--- a/doc/development/rake_tasks.md
+++ b/doc/development/rake_tasks.md
@@ -270,4 +270,4 @@ To generate GraphQL schema files based on the GitLab schema, run:
bundle exec rake gitlab:graphql:schema:dump
```
-This uses graphql-ruby's built-in Rake tasks to generate files in both [IDL](https://www.prisma.io/blog/graphql-sdl-schema-definition-language-6755bcb9ce51) and JSON formats.
+This uses GraphQL Ruby's built-in Rake tasks to generate files in both [IDL](https://www.prisma.io/blog/graphql-sdl-schema-definition-language-6755bcb9ce51) and JSON formats.
diff --git a/doc/development/testing_guide/end_to_end/best_practices.md b/doc/development/testing_guide/end_to_end/best_practices.md
index e1807f2b53f..fbb2a17bef1 100644
--- a/doc/development/testing_guide/end_to_end/best_practices.md
+++ b/doc/development/testing_guide/end_to_end/best_practices.md
@@ -74,7 +74,10 @@ point of failure and so the screenshot would not be captured at the right moment
All QA tests expect to be able to log in at the start of the test.
-That's not possible if a test leaves the browser logged in when it finishes. Normally this isn't a problem because [Capybara resets the session after each test](https://github.com/teamcapybara/capybara/blob/9ebc5033282d40c73b0286e60217515fd1bb0b5d/lib/capybara/rspec.rb#L18). But Capybara does that in an `after` block, so when a test logs in in an `after(:context)` block, the browser returns to a logged in state *after* Capybara had logged it out. And so the next test will fail.
+That's not possible if a test leaves the browser logged in when it finishes. Normally this isn't a
+problem because [Capybara resets the session after each test](https://github.com/teamcapybara/capybara/blob/9ebc5033282d40c73b0286e60217515fd1bb0b5d/lib/capybara/rspec.rb#L18).
+But Capybara does that in an `after` block, so when a test logs in within an `after(:context)` block,
+the browser returns to a logged in state *after* Capybara had logged it out. And so the next test will fail.
For an example see: <https://gitlab.com/gitlab-org/gitlab/issues/34736>
diff --git a/doc/development/testing_guide/end_to_end/quick_start_guide.md b/doc/development/testing_guide/end_to_end/quick_start_guide.md
index ebf0421617f..c721c934033 100644
--- a/doc/development/testing_guide/end_to_end/quick_start_guide.md
+++ b/doc/development/testing_guide/end_to_end/quick_start_guide.md
@@ -458,7 +458,7 @@ By defining the `api_get_path` method, we **would** allow for the [`ApiFabricato
By defining the `api_post_path` method, we allow for the [`ApiFabricator`](https://gitlab.com/gitlab-org/gitlab/blob/master/qa/qa/resource/api_fabricator.rb) module to know which path to use to create a new label in a specific project.
-By defining the `api_post_body` method, we we allow for the [`ApiFabricator.api_post`](https://gitlab.com/gitlab-org/gitlab/blob/a9177ca1812bac57e2b2fa4560e1d5dd8ffac38b/qa/qa/resource/api_fabricator.rb#L68) method to know which data to send when making the `POST` request.
+By defining the `api_post_body` method, we allow for the [`ApiFabricator.api_post`](https://gitlab.com/gitlab-org/gitlab/blob/a9177ca1812bac57e2b2fa4560e1d5dd8ffac38b/qa/qa/resource/api_fabricator.rb#L68) method to know which data to send when making the `POST` request.
> Notice that we pass both `color` and `name` attributes in the `api_post_body` since [those are required](../../../api/labels.md#create-a-new-label). Also, notice that we keep them alphabetically organized.
diff --git a/doc/development/uploads.md b/doc/development/uploads.md
index b26211901b2..fbdb15d82e1 100644
--- a/doc/development/uploads.md
+++ b/doc/development/uploads.md
@@ -1,7 +1,7 @@
# Uploads development documentation
[GitLab Workhorse](https://gitlab.com/gitlab-org/gitlab-workhorse) has special rules for handling uploads.
-To prevent occupying a ruby process on I/O operations, we process the upload in workhorse, where is cheaper.
+To prevent occupying a Ruby process on I/O operations, we process the upload in workhorse, where is cheaper.
This process can also directly upload to object storage.
## The problem description
@@ -40,7 +40,7 @@ We have three challenges here: performance, availability, and scalability.
### Performance
-Rails process are expensive in terms of both CPU and memory. Ruby [global interpreter lock](https://en.wikipedia.org/wiki/Global_interpreter_lock) adds to cost too because the ruby process will spend time on I/O operations on step 3 causing incoming requests to pile up.
+Rails process are expensive in terms of both CPU and memory. Ruby [global interpreter lock](https://en.wikipedia.org/wiki/Global_interpreter_lock) adds to cost too because the Ruby process will spend time on I/O operations on step 3 causing incoming requests to pile up.
In order to improve this, [disk buffered upload](#disk-buffered-upload) was implemented. With this, Rails no longer deals with writing uploaded files to disk.
diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md
index 128d0746df2..a88e8b0c310 100644
--- a/doc/install/aws/index.md
+++ b/doc/install/aws/index.md
@@ -578,7 +578,7 @@ On the EC2 dashboard:
1. Give your image a name and description (we'll use `GitLab-Source` for both).
1. Leave everything else as default and click **Create Image**
-Now we have a custom AMI that we'll use to create our launch configuration the the next step.
+Now we have a custom AMI that we'll use to create our launch configuration the next step.
## Deploying GitLab inside an auto scaling group
diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md
index 47497e7b385..48f39ea4bc9 100644
--- a/doc/integration/elasticsearch.md
+++ b/doc/integration/elasticsearch.md
@@ -610,7 +610,7 @@ Here are some common pitfalls and how to overcome them:
- **My single node Elasticsearch cluster status never goes from `yellow` to `green` even though everything seems to be running properly**
- **For a single node Elasticsearch cluster the functional cluster health status will be yellow** (will never be green) because the primary shard is allocated but replicas can not be as there is no other node to which Elasticsearch can assign a replica. This also applies if you are using using the
+ **For a single node Elasticsearch cluster the functional cluster health status will be yellow** (will never be green) because the primary shard is allocated but replicas can not be as there is no other node to which Elasticsearch can assign a replica. This also applies if you are using the
[Amazon Elasticsearch](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/aes-handling-errors.html#aes-handling-errors-yellow-cluster-status) service.
CAUTION: **Warning**: Setting the number of replicas to `0` is not something that we recommend (this is not allowed in the GitLab Elasticsearch Integration menu). If you are planning to add more Elasticsearch nodes (for a total of more than 1 Elasticsearch) the number of replicas will need to be set to an integer value larger than `0`. Failure to do so will result in lack of redundancy (losing one node will corrupt the index).
diff --git a/doc/integration/gmail_action_buttons_for_gitlab.md b/doc/integration/gmail_action_buttons_for_gitlab.md
index 3c01817032b..1ab01494edc 100644
--- a/doc/integration/gmail_action_buttons_for_gitlab.md
+++ b/doc/integration/gmail_action_buttons_for_gitlab.md
@@ -6,16 +6,18 @@ If correctly set up, emails that require an action will be marked in Gmail.
![gmail_actions_button.png](img/gmail_action_buttons_for_gitlab.png)
-To get this functioning, you need to be registered with Google.
-[See how to register with Google in this document.](https://developers.google.com/gmail/markup/registering-with-google)
+To get this functioning, you need to be registered with Google. For instructions, see
+[Register with Google](https://developers.google.com/gmail/markup/registering-with-google).
*This process has a lot of steps so make sure that you fulfill all requirements set by Google.*
*Your application will be rejected by Google if you fail to do so.*
-Pay close attention to:
+In particular, note:
-- Email account used by GitLab to send notification emails needs to have "Consistent history of sending a high volume of mail from your domain (order of hundred emails a day minimum to Gmail) for a few weeks at least".
-- "A very very low rate of spam complaints from users."
+- The email account used by GitLab to send notification emails must:
+ - Have a "Consistent history of sending a high volume of mail from your domain
+ (order of hundred emails a day minimum to Gmail) for a few weeks at least".
+ - Have a very low rate of spam complaints from users.
- Emails must be authenticated via DKIM or SPF.
- Before sending the final form ("Gmail Schema Whitelist Request"), you must send a real email from your production server. This means that you will have to find a way to send this email from the email address you are registering. You can do this by, for example, forwarding the real email from the email address you are registering or going into the rails console on the GitLab server and triggering the email sending from there.
diff --git a/doc/policy/maintenance.md b/doc/policy/maintenance.md
index 35cea84c129..cf2a7a375cc 100644
--- a/doc/policy/maintenance.md
+++ b/doc/policy/maintenance.md
@@ -90,7 +90,7 @@ based on *all* of the following:
1. Potentially affecting one or more strategic accounts due to a proven inability by the user to upgrade to the current stable version.
If *all* of the above are satisfied, the backport releases can be created for
-the current stable stable release, and two previous monthly releases.
+the current stable release, and two previous monthly releases.
For instance, if we release `11.2.1` with a fix for a severe bug introduced in
`11.0.0`, we could backport the fix to a new `11.0.x`, and `11.1.x` patch release.
@@ -186,7 +186,7 @@ Check [our release posts](https://about.gitlab.com/releases/categories/releases/
Each month, we publish either a major or minor release of GitLab. At the end
of those release posts there are three sections to look for: deprecations, important notes,
-and upgrade barometer. These will will draw your attention to:
+and upgrade barometer. These will draw your attention to:
- Steps you need to perform as part of an upgrade.
For example [8.12](https://about.gitlab.com/releases/2016/09/22/gitlab-8-12-released/#upgrade-barometer)
diff --git a/doc/topics/autodevops/customize.md b/doc/topics/autodevops/customize.md
index 45f28af2192..7efe2c3bdcf 100644
--- a/doc/topics/autodevops/customize.md
+++ b/doc/topics/autodevops/customize.md
@@ -18,6 +18,15 @@ or a `.buildpacks` file in your project:
and add the URL of the buildpack to use on a line in the file. If you want to
use multiple buildpacks, you can enter them in, one on each line.
+The buildpack URL can point to either a Git repository URL or a tarball URL.
+For Git repositories, it is possible to point to a specific Git reference (for example,
+commit SHA, tag name, or branch name) by appending `#<ref>` to the Git repository URL.
+For example:
+
+- The tag `v142`: `https://github.com/heroku/heroku-buildpack-ruby.git#v142`.
+- The branch `mybranch`: `https://github.com/heroku/heroku-buildpack-ruby.git#mybranch`.
+- The commit SHA `f97d8a8ab49`: `https://github.com/heroku/heroku-buildpack-ruby.git#f97d8a8ab49`.
+
### Multiple buildpacks
Using multiple buildpacks isn't fully supported by Auto DevOps because, when using the `.buildpacks`
@@ -291,7 +300,7 @@ applications.
| `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME` | From GitLab 11.11, used to set a username to connect to the Helm repository. Defaults to no credentials. Also set `AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD`. |
| `AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD` | From GitLab 11.11, used to set a password to connect to the Helm repository. Defaults to no credentials. Also set `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME`. |
| `AUTO_DEVOPS_MODSECURITY_SEC_RULE_ENGINE` | From GitLab 12.5, used in combination with [Modsecurity feature flag](../../user/clusters/applications.md#web-application-firewall-modsecurity) to toggle [Modsecurity's `SecRuleEngine`](https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)#SecRuleEngine) behavior. Defaults to `DetectionOnly`. |
-| `BUILDPACK_URL` | Buildpack's full URL. Can point to either Git repositories or a tarball URL. For Git repositories, it is possible to point to a specific `ref`. For example `https://github.com/heroku/heroku-buildpack-ruby.git#v142`. |
+| `BUILDPACK_URL` | Buildpack's full URL. Can point to either [a Git repository URL or a tarball URL](#custom-buildpacks). |
| `CANARY_ENABLED` | From GitLab 11.0, used to define a [deploy policy for canary environments](#deploy-policy-for-canary-environments-premium). |
| `CANARY_PRODUCTION_REPLICAS` | Number of canary replicas to deploy for [Canary Deployments](../../user/project/canary_deployments.md) in the production environment. Takes precedence over `CANARY_REPLICAS`. Defaults to 1. |
| `CANARY_REPLICAS` | Number of canary replicas to deploy for [Canary Deployments](../../user/project/canary_deployments.md). Defaults to 1. |
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index e0645a28fff..043bb0dfcfa 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -420,7 +420,7 @@ spec:
- Auto Build and Auto Test may fail in detecting your language/framework. There
may be no buildpack for your application, or your application may be missing the
- key files the buildpack is looking for. For example, for ruby apps, you must
+ key files the buildpack is looking for. For example, for Ruby applications, you must
have a `Gemfile` to be properly detected, even though it is possible to write a
Ruby app without a `Gemfile`. Try specifying a [custom
buildpack](customize.md#custom-buildpacks).
diff --git a/doc/topics/git/useful_git_commands.md b/doc/topics/git/useful_git_commands.md
index 2cec0cd04f7..63defb24eaf 100644
--- a/doc/topics/git/useful_git_commands.md
+++ b/doc/topics/git/useful_git_commands.md
@@ -5,7 +5,7 @@ type: reference
# Useful Git commands
Here are some useful Git commands collected by the GitLab support team. You may not
-need to use often, but they can can come in handy when needed.
+need to use often, but they can come in handy when needed.
## Remotes
diff --git a/doc/user/admin_area/merge_requests_approvals.md b/doc/user/admin_area/merge_requests_approvals.md
index 4138dc27066..0c7beadad48 100644
--- a/doc/user/admin_area/merge_requests_approvals.md
+++ b/doc/user/admin_area/merge_requests_approvals.md
@@ -23,11 +23,11 @@ GitLab administrators can later override these settings in a project’s setting
Merge request approval rules that can be set at an instance level are:
-- **Prevent approval of merge requests by merge request author**. Prevents non-admins
- from allowing merge request authors to merge their own merge requests in individual
- projects.
-- **Prevent approval of merge requests by merge request committers**. Prevents
- non-admins from allowing merge request committers to merge merge requests they were
- committing to in individual projects.
-- **Prevent users from modifying merge request approvers list**. Prevents non-admins
- from modifying approvers list in project settings and in individual merge requests.
+- **Prevent approval of merge requests by merge request author**. Prevents project
+ maintainers from allowing request authors to merge their own merge requests.
+- **Prevent approval of merge requests by merge request committers**. Prevents project
+ maintainers from allowing users to approve merge requests if they have submitted
+ any commits to the source branch.
+- **Prevent users from modifying merge request approvers list**. Prevents project
+ maintainers from allowing users to modify the approvers list in project settings
+ or in individual merge requests.
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index f2b7c30b5cc..c65d6adcff6 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -495,7 +495,7 @@ The DAST job can emit various reports.
CAUTION: **Caution:**
The JSON report artifacts are not a public API of DAST and their format is expected to change in the future.
-The DAST tool always emits a JSON report report file called `gl-dast-report.json` and sample reports can be found in the [DAST repository](https://gitlab.com/gitlab-org/security-products/dast/-/tree/master/test/end-to-end/expect).
+The DAST tool always emits a JSON report file called `gl-dast-report.json` and sample reports can be found in the [DAST repository](https://gitlab.com/gitlab-org/security-products/dast/-/tree/master/test/end-to-end/expect).
There are two formats of data in the JSON report that are used side by side: the proprietary ZAP format which will be eventually deprecated, and a "common" format which will be the default in the future.
diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md
index 252abc9295f..9cd2e9d4e62 100644
--- a/doc/user/application_security/sast/index.md
+++ b/doc/user/application_security/sast/index.md
@@ -352,7 +352,7 @@ analyzer containers: `DOCKER_`, `CI`, `GITLAB_`, `FF_`, `HOME`, `PWD`, `OLDPWD`,
CAUTION: **Caution:**
The JSON report artifacts are not a public API of SAST and their format may change in the future.
-The SAST tool emits a JSON report report file. Here is an example of the report structure with all important parts of
+The SAST tool emits a JSON report file. Here is an example of the report structure with all important parts of
it highlighted:
```json-doc
diff --git a/doc/user/clusters/management_project.md b/doc/user/clusters/management_project.md
index f5be8a3f5f3..2b8ed83bdb2 100644
--- a/doc/user/clusters/management_project.md
+++ b/doc/user/clusters/management_project.md
@@ -27,7 +27,7 @@ Management projects are restricted to the following:
- For project-level clusters, the management project must be in the same
namespace (or descendants) as the cluster's project.
- For group-level clusters, the management project must be in the same
- group (or descendants) as as the cluster's group.
+ group (or descendants) as the cluster's group.
- For instance-level clusters, there are no such restrictions.
## Usage
diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md
index 7621679c6cc..308a7b2cb4a 100644
--- a/doc/user/group/saml_sso/index.md
+++ b/doc/user/group/saml_sso/index.md
@@ -281,7 +281,7 @@ GitLab [isn't limited to the SAML providers listed above](#my-identity-provider-
| Additional URLs | | You may need to use the `Identifier` or `Assertion consumer service URL` in other fields on some providers. |
| Single Sign Out URL | | Not supported |
-If the information information you need isn't listed above you may wish to check our [troubleshooting docs below](#i-need-additional-information-to-configure-my-identity-provider).
+If the information you need isn't listed above you may wish to check our [troubleshooting docs below](#i-need-additional-information-to-configure-my-identity-provider).
## Linking SAML to your existing GitLab.com account
diff --git a/doc/user/packages/npm_registry/index.md b/doc/user/packages/npm_registry/index.md
index 7b97933aa89..e66b3d1ac63 100644
--- a/doc/user/packages/npm_registry/index.md
+++ b/doc/user/packages/npm_registry/index.md
@@ -244,7 +244,7 @@ Registry.
## Installing a package
-NPM packages are commonly installed using the the `npm` or `yarn` commands
+NPM packages are commonly installed using the `npm` or `yarn` commands
inside a JavaScript project. If you haven't already, you will need to set the
URL for scoped packages. You can do this with the following command:
diff --git a/doc/user/profile/notifications.md b/doc/user/profile/notifications.md
index 3f843bf8b5e..1d92f15552d 100644
--- a/doc/user/profile/notifications.md
+++ b/doc/user/profile/notifications.md
@@ -222,7 +222,7 @@ The following table lists all GitLab-specific email headers:
### X-GitLab-NotificationReason
-The `X-GitLab-NotificationReason` header contains the reason for the notification. The value is one of the the following, in order of priority:
+The `X-GitLab-NotificationReason` header contains the reason for the notification. The value is one of the following, in order of priority:
- `own_activity`
- `assigned`
diff --git a/doc/user/project/clusters/add_eks_clusters.md b/doc/user/project/clusters/add_eks_clusters.md
index 82b3cb49075..7fa8ec6c5f3 100644
--- a/doc/user/project/clusters/add_eks_clusters.md
+++ b/doc/user/project/clusters/add_eks_clusters.md
@@ -245,7 +245,7 @@ To add an existing EKS cluster to your project, group, or instance:
token: <authentication_token>
```
- 1. Locate the the API server endpoint so GitLab can connect to the cluster. This is displayed on
+ 1. Locate the API server endpoint so GitLab can connect to the cluster. This is displayed on
the AWS EKS console, when viewing the EKS cluster details.
1. Navigate to your:
- Project's **{cloud-gear}** **Operations > Kubernetes** page, for a project-level cluster.
diff --git a/doc/user/project/highlighting.md b/doc/user/project/highlighting.md
index 85992e1301f..2bdb0ae2706 100644
--- a/doc/user/project/highlighting.md
+++ b/doc/user/project/highlighting.md
@@ -10,7 +10,7 @@ If GitLab is guessing wrong, you can override its choice of language using the `
When you check in and push that change, all `*.pl` files in your project will be highlighted as Prolog.
-The paths here are simply Git's built-in [`.gitattributes` interface](https://git-scm.com/docs/gitattributes). So, if you were to invent a file format called a `Nicefile` at the root of your project that used ruby syntax, all you need is:
+The paths here are simply Git's built-in [`.gitattributes` interface](https://git-scm.com/docs/gitattributes). So, if you were to invent a file format called a `Nicefile` at the root of your project that used Ruby syntax, all you need is:
``` conf
/Nicefile gitlab-language=ruby
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index bbed9ae4686..273ab9095c0 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -397,7 +397,7 @@ Starting in [version 12.8](https://gitlab.com/gitlab-org/gitlab/issues/202696),
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/16530) in GitLab 12.5.
-To add an anomaly chart panel type to a dashboard, add add a panel with *exactly* 3 metrics.
+To add an anomaly chart panel type to a dashboard, add a panel with *exactly* 3 metrics.
The first metric represents the current state, and the second and third metrics represent the upper and lower limit respectively:
diff --git a/doc/user/project/merge_requests/creating_merge_requests.md b/doc/user/project/merge_requests/creating_merge_requests.md
index e8c691a3d7f..d8a2b427288 100644
--- a/doc/user/project/merge_requests/creating_merge_requests.md
+++ b/doc/user/project/merge_requests/creating_merge_requests.md
@@ -28,7 +28,7 @@ button and start a merge request from there.
## New Merge Request page
On the **New Merge Request** page, start by filling in the title
-and description for the merge request. If there are are already
+and description for the merge request. If there are already
commits on the branch, the title will be prefilled with the first
line of the first commit message, and the description will be
prefilled with any additional lines in the commit message.
diff --git a/doc/user/project/operations/feature_flags.md b/doc/user/project/operations/feature_flags.md
index 86d8e829648..f13fbcb2722 100644
--- a/doc/user/project/operations/feature_flags.md
+++ b/doc/user/project/operations/feature_flags.md
@@ -175,10 +175,10 @@ a number of community contributed libraries.
Official clients:
-- [unleash/unleash-client-java](https://github.com/unleash/unleash-client-java)
-- [unleash/unleash-client-node](https://github.com/unleash/unleash-client-node)
-- [unleash/unleash-client-go](https://github.com/unleash/unleash-client-go)
-- [unleash/unleash-client-ruby](https://github.com/unleash/unleash-client-ruby)
+- [Unleash client SDK for Java](https://github.com/unleash/unleash-client-java)
+- [Unleash client SDK for Node.js](https://github.com/unleash/unleash-client-node)
+- [Unleash client for Go](https://github.com/unleash/unleash-client-go)
+- [Unleash client for Ruby](https://github.com/unleash/unleash-client-ruby)
Community contributed clients:
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 01ecfff8ffd..38c0eb5d83d 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -19172,6 +19172,30 @@ msgstr ""
msgid "Static Application Security Testing (SAST)"
msgstr ""
+msgid "StaticSiteEditor|A merge request was created:"
+msgstr ""
+
+msgid "StaticSiteEditor|A new branch was created:"
+msgstr ""
+
+msgid "StaticSiteEditor|Return to site"
+msgstr ""
+
+msgid "StaticSiteEditor|Success!"
+msgstr ""
+
+msgid "StaticSiteEditor|Summary of changes"
+msgstr ""
+
+msgid "StaticSiteEditor|View merge request"
+msgstr ""
+
+msgid "StaticSiteEditor|Your changes have been submitted and a merge request has been created. The changes won’t be visible on the site until the merge request has been accepted."
+msgstr ""
+
+msgid "StaticSiteEditor|Your changes were committed to it:"
+msgstr ""
+
msgid "Statistics"
msgstr ""
diff --git a/spec/frontend/static_site_editor/components/saved_changes_message_spec.js b/spec/frontend/static_site_editor/components/saved_changes_message_spec.js
new file mode 100644
index 00000000000..76ac7de5c32
--- /dev/null
+++ b/spec/frontend/static_site_editor/components/saved_changes_message_spec.js
@@ -0,0 +1,61 @@
+import { shallowMount } from '@vue/test-utils';
+import SavedChangesMessage from '~/static_site_editor/components/saved_changes_message.vue';
+
+describe('~/static_site_editor/components/saved_changes_message.vue', () => {
+ let wrapper;
+ const props = {
+ branch: {
+ label: '123-the-branch',
+ url: 'https://gitlab.com/gitlab-org/gitlab/-/tree/123-the-branch',
+ },
+ commit: {
+ label: 'a123',
+ url: 'https://gitlab.com/gitlab-org/gitlab/-/commit/a123',
+ },
+ mergeRequest: {
+ label: '123',
+ url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123',
+ },
+ returnUrl: 'https://www.the-static-site.com/post',
+ };
+ const findReturnToSiteButton = () => wrapper.find({ ref: 'returnToSiteButton' });
+ const findMergeRequestButton = () => wrapper.find({ ref: 'mergeRequestButton' });
+ const findBranchLink = () => wrapper.find({ ref: 'branchLink' });
+ const findCommitLink = () => wrapper.find({ ref: 'commitLink' });
+ const findMergeRequestLink = () => wrapper.find({ ref: 'mergeRequestLink' });
+
+ beforeEach(() => {
+ wrapper = shallowMount(SavedChangesMessage, {
+ propsData: props,
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it.each`
+ text | findEl | url
+ ${'Return to site'} | ${findReturnToSiteButton} | ${props.returnUrl}
+ ${'View merge request'} | ${findMergeRequestButton} | ${props.mergeRequest.url}
+ `('renders "$text" button link', ({ text, findEl, url }) => {
+ const btn = findEl();
+
+ expect(btn.exists()).toBe(true);
+ expect(btn.text()).toBe(text);
+ expect(btn.attributes('href')).toBe(url);
+ });
+
+ it.each`
+ desc | findEl | prop
+ ${'branch'} | ${findBranchLink} | ${props.branch}
+ ${'commit'} | ${findCommitLink} | ${props.commit}
+ ${'merge request'} | ${findMergeRequestLink} | ${props.mergeRequest}
+ `('renders $desc link', ({ findEl, prop }) => {
+ const el = findEl();
+
+ expect(el.exists()).toBe(true);
+ expect(el.attributes('href')).toBe(prop.url);
+ expect(el.text()).toBe(prop.label);
+ });
+});
diff --git a/spec/graphql/resolvers/projects/services_resolver_spec.rb b/spec/graphql/resolvers/projects/services_resolver_spec.rb
new file mode 100644
index 00000000000..00045442ea0
--- /dev/null
+++ b/spec/graphql/resolvers/projects/services_resolver_spec.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Resolvers::Projects::ServicesResolver do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ let_it_be(:user) { create(:user) }
+
+ context 'when project does not have services' do
+ let_it_be(:project) { create(:project, :private) }
+
+ context 'when user cannot access services' do
+ context 'when anonymous user' do
+ it_behaves_like 'cannot access project services'
+ end
+
+ context 'when user developer' do
+ before do
+ project.add_developer(user)
+ end
+
+ it_behaves_like 'cannot access project services'
+ end
+ end
+
+ context 'when user can read project services' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it_behaves_like 'no project services'
+ end
+ end
+
+ context 'when project has services' do
+ let_it_be(:project) { create(:project, :private) }
+ let_it_be(:jira_service) { create(:jira_service, project: project) }
+
+ context 'when user cannot access services' do
+ context 'when anonymous user' do
+ it_behaves_like 'cannot access project services'
+ end
+
+ context 'when user developer' do
+ before do
+ project.add_developer(user)
+ end
+
+ it_behaves_like 'cannot access project services'
+ end
+ end
+
+ context 'when user can read project services' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'returns project services' do
+ services = resolve_services
+
+ expect(services.size).to eq 1
+ end
+ end
+ end
+ end
+
+ def resolve_services(args = {}, context = { current_user: user })
+ resolve(described_class, obj: project, args: args, ctx: context)
+ end
+end
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index 0c8be50ed90..6ea852190c9 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -24,7 +24,7 @@ describe GitlabSchema.types['Project'] do
namespace group statistics repository merge_requests merge_request issues
issue pipelines removeSourceBranchAfterMerge sentryDetailedError snippets
grafanaIntegration autocloseReferencedIssues suggestion_commit_message environments
- boards jira_import_status jira_imports
+ boards jira_import_status jira_imports services
]
expect(described_class).to include_graphql_fields(*expected_fields)
@@ -84,4 +84,16 @@ describe GitlabSchema.types['Project'] do
it { is_expected.to have_graphql_type(Types::BoardType.connection_type) }
end
+
+ describe 'jira_imports field' do
+ subject { described_class.fields['jiraImports'] }
+
+ it { is_expected.to have_graphql_type(Types::JiraImportType.connection_type) }
+ end
+
+ describe 'services field' do
+ subject { described_class.fields['services'] }
+
+ it { is_expected.to have_graphql_type(Types::Projects::ServiceType.connection_type) }
+ end
end
diff --git a/spec/graphql/types/projects/base_service_type_spec.rb b/spec/graphql/types/projects/base_service_type_spec.rb
new file mode 100644
index 00000000000..bda6022bf79
--- /dev/null
+++ b/spec/graphql/types/projects/base_service_type_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe GitlabSchema.types['BaseService'] do
+ it { expect(described_class.graphql_name).to eq('BaseService') }
+
+ it 'has basic expected fields' do
+ expect(described_class).to have_graphql_fields(:type, :active)
+ end
+
+ it { expect(described_class).to require_graphql_authorizations(:admin_project) }
+end
diff --git a/spec/graphql/types/projects/jira_service_type_spec.rb b/spec/graphql/types/projects/jira_service_type_spec.rb
new file mode 100644
index 00000000000..7f8fa6538e9
--- /dev/null
+++ b/spec/graphql/types/projects/jira_service_type_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe GitlabSchema.types['JiraService'] do
+ it { expect(described_class.graphql_name).to eq('JiraService') }
+
+ it 'has basic expected fields' do
+ expect(described_class).to have_graphql_fields(:type, :active)
+ end
+
+ it { expect(described_class).to require_graphql_authorizations(:admin_project) }
+end
diff --git a/spec/graphql/types/projects/service_type_spec.rb b/spec/graphql/types/projects/service_type_spec.rb
new file mode 100644
index 00000000000..ad30a4008bc
--- /dev/null
+++ b/spec/graphql/types/projects/service_type_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Types::Projects::ServiceType do
+ it { expect(described_class).to have_graphql_fields(:type, :active) }
+
+ describe ".resolve_type" do
+ it 'resolves the corresponding type for objects' do
+ expect(described_class.resolve_type(build(:jira_service), {})).to eq(Types::Projects::Services::JiraServiceType)
+ expect(described_class.resolve_type(build(:service), {})).to eq(Types::Projects::Services::BaseServiceType)
+ expect(described_class.resolve_type(build(:alerts_service), {})).to eq(Types::Projects::Services::BaseServiceType)
+ expect(described_class.resolve_type(build(:custom_issue_tracker_service), {})).to eq(Types::Projects::Services::BaseServiceType)
+ end
+ end
+end
diff --git a/spec/graphql/types/projects/services_enum_spec.rb b/spec/graphql/types/projects/services_enum_spec.rb
new file mode 100644
index 00000000000..aac4aae4f69
--- /dev/null
+++ b/spec/graphql/types/projects/services_enum_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe GitlabSchema.types['ServiceType'] do
+ it { expect(described_class.graphql_name).to eq('ServiceType') }
+
+ it 'exposes all the existing project services' do
+ expect(described_class.values.keys).to match_array(available_services_enum)
+ end
+end
+
+def available_services_enum
+ ::Service.services_types.map(&:underscore).map(&:upcase)
+end
diff --git a/spec/requests/api/graphql/project/base_service_spec.rb b/spec/requests/api/graphql/project/base_service_spec.rb
new file mode 100644
index 00000000000..8199f331fbf
--- /dev/null
+++ b/spec/requests/api/graphql/project/base_service_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'query Jira service' do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:jira_service) { create(:jira_service, project: project) }
+ let_it_be(:bugzilla_service) { create(:bugzilla_service, project: project) }
+ let_it_be(:redmine_service) { create(:redmine_service, project: project) }
+
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ services {
+ nodes {
+ type
+ active
+ }
+ }
+ }
+ }
+ )
+ end
+
+ let(:services) { graphql_data.dig('project', 'services', 'nodes')}
+
+ it_behaves_like 'unauthorized users cannot read services'
+
+ context 'when user can access project services' do
+ before do
+ project.add_maintainer(current_user)
+ post_graphql(query, current_user: current_user)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'retuns list of jira imports' do
+ service_types = services.map { |s| s['type'] }
+
+ expect(service_types).to match_array(%w(BugzillaService JiraService RedmineService))
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/project/jira_service_spec.rb b/spec/requests/api/graphql/project/jira_service_spec.rb
new file mode 100644
index 00000000000..4ac598b789f
--- /dev/null
+++ b/spec/requests/api/graphql/project/jira_service_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'query Jira service' do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:jira_service) { create(:jira_service, project: project) }
+
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ services(active: true, type: JIRA_SERVICE) {
+ nodes {
+ type
+ }
+ }
+ }
+ }
+ )
+ end
+
+ let(:services) { graphql_data.dig('project', 'services', 'nodes')}
+
+ it_behaves_like 'unauthorized users cannot read services'
+
+ context 'when user can access project services' do
+ before do
+ project.add_maintainer(current_user)
+ post_graphql(query, current_user: current_user)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'retuns list of jira imports' do
+ service = services.first
+
+ expect(service['type']).to eq('JiraService')
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/project_query_spec.rb b/spec/requests/api/graphql/project_query_spec.rb
index fbb22958d51..035894c8022 100644
--- a/spec/requests/api/graphql/project_query_spec.rb
+++ b/spec/requests/api/graphql/project_query_spec.rb
@@ -9,7 +9,27 @@ describe 'getting project information' do
let(:current_user) { create(:user) }
let(:query) do
- graphql_query_for('project', 'fullPath' => project.full_path)
+ graphql_query_for(
+ 'project',
+ { 'fullPath' => project.full_path },
+ all_graphql_fields_for('project'.to_s.classify, excluded: %w(jiraImports services))
+ )
+ end
+
+ context 'when the user has full access to the project' do
+ let(:full_access_query) do
+ graphql_query_for('project', 'fullPath' => project.full_path)
+ end
+
+ before do
+ project.add_maintainer(current_user)
+ end
+
+ it 'includes the project' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data['project']).not_to be_nil
+ end
end
context 'when the user has access to the project' do
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index 74582df6cd9..fc543186b08 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -149,7 +149,7 @@ module GraphqlHelpers
FIELDS
end
- def all_graphql_fields_for(class_name, parent_types = Set.new, max_depth: 3)
+ def all_graphql_fields_for(class_name, parent_types = Set.new, max_depth: 3, excluded: [])
# pulling _all_ fields can generate a _huge_ query (like complexity 180,000),
# and significantly increase spec runtime. so limit the depth by default
return if max_depth <= 0
@@ -165,6 +165,7 @@ module GraphqlHelpers
type.fields.map do |name, field|
# We can't guess arguments, so skip fields that require them
next if required_arguments?(field)
+ next if excluded.include?(name)
singular_field_type = field_type(field)
diff --git a/spec/support/shared_examples/graphql/projects/services_resolver_shared_examples.rb b/spec/support/shared_examples/graphql/projects/services_resolver_shared_examples.rb
new file mode 100644
index 00000000000..4bed322564a
--- /dev/null
+++ b/spec/support/shared_examples/graphql/projects/services_resolver_shared_examples.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+shared_examples 'no project services' do
+ it 'returns empty collection' do
+ expect(resolve_services).to eq []
+ end
+end
+
+shared_examples 'cannot access project services' do
+ it 'raises error' do
+ expect do
+ resolve_services
+ end.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/graphql/projects/services_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/projects/services_shared_examples.rb
new file mode 100644
index 00000000000..246f1850c3c
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/graphql/projects/services_shared_examples.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+shared_examples 'unauthorized users cannot read services' do
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+
+ context 'when anonymous user' do
+ let(:current_user) { nil }
+
+ it { expect(services).to be nil }
+ end
+
+ context 'when user developer' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ it { expect(services).to be nil }
+ end
+end