Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-05-19 18:08:11 +00:00
parent f2151c65d5
commit d84f18d66c
54 changed files with 753 additions and 262 deletions

View File

@ -45,22 +45,24 @@ export default {
:markdown-docs-path="markdownDocsPath"
:can-attach-file="canAttachFile"
:enable-autocomplete="enableAutocomplete"
:textarea-value="formState.description"
>
<textarea
id="issue-description"
ref="textarea"
slot="textarea"
v-model="formState.description"
class="note-textarea js-gfm-input js-autosize markdown-area
qa-description-textarea"
dir="auto"
data-supports-quick-actions="false"
:aria-label="__('Description')"
:placeholder="__('Write a comment or drag your files here…')"
@keydown.meta.enter="updateIssuable"
@keydown.ctrl.enter="updateIssuable"
>
</textarea>
<template #textarea>
<textarea
id="issue-description"
ref="textarea"
v-model="formState.description"
class="note-textarea js-gfm-input js-autosize markdown-area
qa-description-textarea"
dir="auto"
data-supports-quick-actions="false"
:aria-label="__('Description')"
:placeholder="__('Write a comment or drag your files here…')"
@keydown.meta.enter="updateIssuable"
@keydown.ctrl.enter="updateIssuable"
>
</textarea>
</template>
</markdown-field>
</div>
</template>

View File

@ -14,13 +14,7 @@ import axios from '~/lib/utils/axios_utils';
Vue.use(Translate);
export default () => {
const { dataset } = document.querySelector('.js-pipeline-details-vue');
const mediator = new PipelinesMediator({ endpoint: dataset.endpoint });
mediator.fetchPipeline();
const createPipelinesDetailApp = mediator => {
// eslint-disable-next-line no-new
new Vue({
el: '#js-pipeline-graph-vue',
@ -50,7 +44,9 @@ export default () => {
});
},
});
};
const createPipelineHeaderApp = mediator => {
// eslint-disable-next-line no-new
new Vue({
el: '#js-pipeline-header-vue',
@ -94,7 +90,9 @@ export default () => {
});
},
});
};
const createPipelinesTabs = dataset => {
const tabsElement = document.querySelector('.pipelines-tabs');
const testReportsEnabled =
window.gon && window.gon.features && window.gon.features.junitPipelineView;
@ -119,27 +117,40 @@ export default () => {
tabsElement.addEventListener('click', tabClickHandler);
}
// eslint-disable-next-line no-new
new Vue({
el: '#js-pipeline-tests-detail',
components: {
TestReports,
},
render(createElement) {
return createElement('test-reports');
},
});
axios
.get(dataset.testReportsCountEndpoint)
.then(({ data }) => {
if (!data.total_count) {
return;
}
document.querySelector('.js-test-report-badge-counter').innerHTML = data.total_count;
})
.catch(() => {});
}
};
const createTestDetails = detailsEndpoint => {
// eslint-disable-next-line no-new
new Vue({
el: '#js-pipeline-tests-detail',
components: {
TestReports,
},
render(createElement) {
return createElement('test-reports');
},
});
axios
.get(detailsEndpoint)
.then(({ data }) => {
if (!data.total_count) {
return;
}
document.querySelector('.js-test-report-badge-counter').innerHTML = data.total_count;
})
.catch(() => {});
};
export default () => {
const { dataset } = document.querySelector('.js-pipeline-details-vue');
const mediator = new PipelinesMediator({ endpoint: dataset.endpoint });
mediator.fetchPipeline();
createPipelinesDetailApp(mediator);
createPipelineHeaderApp(mediator);
createPipelinesTabs(dataset);
createTestDetails(dataset.testReportsCountEndpoint);
};

View File

@ -56,7 +56,7 @@
min-height: 68px;
&:last-child {
background-color: $gray-normal;
background-color: $gray-10;
&::before {
content: none !important;

View File

@ -0,0 +1,48 @@
# frozen_string_literal: true
class Admin::Ci::VariablesController < Admin::ApplicationController
def show
respond_to do |format|
format.json { render_instance_variables }
end
end
def update
service = Ci::UpdateInstanceVariablesService.new(variables_params)
if service.execute
respond_to do |format|
format.json { render_instance_variables }
end
else
respond_to do |format|
format.json { render_error(service.errors) }
end
end
end
private
def variables
@variables ||= Ci::InstanceVariable.all
end
def render_instance_variables
render status: :ok,
json: {
variables: Ci::InstanceVariableSerializer.new.represent(variables)
}
end
def render_error(errors)
render status: :bad_request, json: errors
end
def variables_params
params.permit(variables_attributes: [*variable_params_attributes])
end
def variable_params_attributes
%i[id variable_type key secret_value protected masked _destroy]
end
end

View File

@ -34,8 +34,6 @@ class Release < ApplicationRecord
delegate :repository, to: :project
after_commit :notify_new_release, on: :create, unless: :importing?
MAX_NUMBER_TO_DISPLAY = 3
def to_param
@ -92,10 +90,6 @@ class Release < ApplicationRecord
repository.find_tag(tag)
end
end
def notify_new_release
NewReleaseWorker.perform_async(id)
end
end
Release.prepend_if_ee('EE::Release')

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
module Ci
class BasicVariableEntity < Grape::Entity
expose :id
expose :key
expose :value
expose :variable_type
expose :protected?, as: :protected
expose :masked?, as: :masked
end
end

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
module Ci
class InstanceVariableSerializer < BaseSerializer
entity BasicVariableEntity
end
end

View File

@ -1,11 +1,4 @@
# frozen_string_literal: true
class GroupVariableEntity < Grape::Entity
expose :id
expose :key
expose :value
expose :variable_type
expose :protected?, as: :protected
expose :masked?, as: :masked
class GroupVariableEntity < Ci::BasicVariableEntity
end

View File

@ -1,12 +1,5 @@
# frozen_string_literal: true
class VariableEntity < Grape::Entity
expose :id
expose :key
expose :value
expose :variable_type
expose :protected?, as: :protected
expose :masked?, as: :masked
class VariableEntity < Ci::BasicVariableEntity
expose :environment_scope
end

View File

@ -0,0 +1,72 @@
# frozen_string_literal: true
# This class is a simplified version of assign_nested_attributes_for_collection_association from ActiveRecord
# https://github.com/rails/rails/blob/v6.0.2.1/activerecord/lib/active_record/nested_attributes.rb#L466
module Ci
class UpdateInstanceVariablesService
UNASSIGNABLE_KEYS = %w(id _destroy).freeze
def initialize(params)
@params = params[:variables_attributes]
end
def execute
instantiate_records
persist_records
end
def errors
@records.to_a.flat_map { |r| r.errors.full_messages }
end
private
attr_reader :params
def existing_records_by_id
@existing_records_by_id ||= Ci::InstanceVariable
.all
.index_by { |var| var.id.to_s }
end
def instantiate_records
@records = params.map do |attributes|
find_or_initialize_record(attributes).tap do |record|
record.assign_attributes(attributes.except(*UNASSIGNABLE_KEYS))
record.mark_for_destruction if has_destroy_flag?(attributes)
end
end
end
def find_or_initialize_record(attributes)
id = attributes[:id].to_s
if id.blank?
Ci::InstanceVariable.new
else
existing_records_by_id.fetch(id) { raise ActiveRecord::RecordNotFound }
end
end
def persist_records
Ci::InstanceVariable.transaction do
success = @records.map do |record|
if record.marked_for_destruction?
record.destroy
else
record.save
end
end.all?
raise ActiveRecord::Rollback unless success
success
end
end
def has_destroy_flag?(hash)
Gitlab::Utils.to_boolean(hash['_destroy'])
end
end
end

View File

@ -47,11 +47,17 @@ module Releases
release.save!
notify_create_release(release)
success(tag: tag, release: release)
rescue => e
error(e.message, 400)
end
def notify_create_release(release)
NotificationService.new.async.send_new_release_notifications(release)
end
def build_release(tag)
project.releases.build(
name: name,

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true
# TODO: Worker can be removed in 13.2:
# https://gitlab.com/gitlab-org/gitlab/-/issues/218231
class NewReleaseWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker

View File

@ -0,0 +1,5 @@
---
title: Add admin controller actions for interacting with instance variables
merge_request: 30385
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Update alert management table background colour to correct gray
merge_request: 32068
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Move release notification from model callbacks to service
merge_request: 29853
author: Ravishankar
type: performance

View File

@ -0,0 +1,5 @@
---
title: Update deprecated slot syntax in ./app/assets/javascripts/issue_show/components/fields/description.vue
merge_request: 31979
author: Gilang Gumilar
type: other

View File

@ -154,6 +154,10 @@ namespace :admin do
end
end
namespace :ci do
resource :variables, only: [:show, :update]
end
concerns :clusterable
get '/dashboard/stats', to: 'dashboard#stats'

View File

@ -499,7 +499,7 @@ to start again from scratch, there are a few steps that can help you:
1. Refresh Foreign Data Wrapper tables
```sh
```shell
gitlab-rake geo:db:refresh_foreign_tables
```

View File

@ -226,6 +226,9 @@ incoming_email:
Example configuration for Gmail/G Suite. Assumes mailbox `gitlab-incoming@gmail.com`.
NOTE: **Note:**
`incoming_email_email` cannot be a Gmail alias account.
Example for Omnibus installs:
```ruby

View File

@ -716,7 +716,7 @@ built-in command:
If you did not change the default location of the configuration file, run:
```sh
```shell
sudo gitlab-ctl registry-garbage-collect
```
@ -725,7 +725,7 @@ layers you have stored.
If you changed the location of the Container Registry `config.yml`:
```sh
```shell
sudo gitlab-ctl registry-garbage-collect /path/to/config.yml
```
@ -749,7 +749,7 @@ referenced by the registry tag. The `registry-garbage-collect` command supports
`-m` switch to allow you to remove all unreferenced manifests and layers that are
not directly accessible via `tag`:
```sh
```shell
sudo gitlab-ctl registry-garbage-collect -m
```
@ -787,7 +787,7 @@ To enable the read-only mode:
1. Save and reconfigure GitLab:
```sh
```shell
sudo gitlab-ctl reconfigure
```
@ -795,7 +795,7 @@ To enable the read-only mode:
1. Next, trigger one of the garbage collect commands:
```sh
```shell
# Recycling unused tags
sudo /opt/gitlab/embedded/bin/registry garbage-collect /var/opt/gitlab/registry/config.yml
@ -822,7 +822,7 @@ To enable the read-only mode:
1. Save and reconfigure GitLab:
```sh
```shell
sudo gitlab-ctl reconfigure
```

View File

@ -63,7 +63,7 @@ other CDNs or Function as a Service (FaaS) systems should work using the same pr
`pwgen -cn1 64` on a UNIX machine). Save this token for the admin panel, as
described in the [configuring](#configuring) section.
```js
```javascript
const ORIGIN_HOSTNAME = 'gitlab.installation.com' // FIXME: SET CORRECT VALUE
const STORAGE_TOKEN = 'very-secure-token' // FIXME: SET CORRECT VALUE
const CACHE_PRIVATE_OBJECTS = false

View File

@ -16,19 +16,19 @@ include use cases targeted for parsing GitLab log files.
#### Pipe colorized `jq` output into `less`
```sh
```shell
jq . <FILE> -C | less -R
```
#### Search for a term and pretty-print all matching lines
```sh
```shell
grep <TERM> <FILE> | jq .
```
#### Skip invalid lines of JSON
```sh
```shell
jq -cR 'fromjson?' file.json | jq <COMMAND>
```
@ -39,49 +39,49 @@ This skips over all invalid lines and parses the rest.
#### Find all requests with a 5XX status code
```sh
```shell
jq 'select(status >= 500)' <FILE>
```
#### Top 10 slowest requests
```sh
```shell
jq -s 'sort_by(-.duration) | limit(10; .[])' <FILE>
```
#### Find and pretty print all requests related to a project
```sh
```shell
grep <PROJECT_NAME> <FILE> | jq .
```
#### Find all requests with a total duration > 5 seconds
```sh
```shell
jq 'select(.duration > 5000)' <FILE>
```
#### Find all project requests with more than 5 rugged calls
```sh
```shell
grep <PROJECT_NAME> <FILE> | jq 'select(.rugged_calls > 5)'
```
#### Find all requests with a Gitaly duration > 10 seconds
```sh
```shell
jq 'select(.gitaly_duration > 10000)' <FILE>
```
#### Find all requests with a queue duration > 10 seconds
```sh
```shell
jq 'select(.queue_duration > 10000)' <FILE>
```
#### Top 10 requests by # of Gitaly calls
```sh
```shell
jq -s 'map(select(.gitaly_calls != null)) | sort_by(-.gitaly_calls) | limit(10; .[])' <FILE>
```
@ -89,7 +89,7 @@ jq -s 'map(select(.gitaly_calls != null)) | sort_by(-.gitaly_calls) | limit(10;
#### Print the top three controller methods by request volume and their three longest durations
```sh
```shell
jq -s -r 'group_by(.controller+.action) | sort_by(-length) | limit(3; .[]) | sort_by(-.duration) | "CT: \(length)\tMETHOD: \(.[0].controller)#\(.[0].action)\tDURS: \(.[0].duration), \(.[1].duration), \(.[2].duration)"' production_json.log
```
@ -105,7 +105,7 @@ CT: 1328 METHOD: Projects::NotesController#index DURS: 403.99, 386.29, 384.3
#### Print top three routes with request count and their three longest durations
```sh
```shell
jq -s -r 'group_by(.route) | sort_by(-length) | limit(3; .[]) | sort_by(-.duration) | "CT: \(length)\tROUTE: \(.[0].route)\tDURS: \(.[0].duration), \(.[1].duration), \(.[2].duration)"' api_json.log
```
@ -121,25 +121,25 @@ CT: 190 ROUTE: /api/:version/projects/:id/repository/commits DURS: 1079.02,
#### Find all Gitaly requests sent from web UI
```sh
```shell
jq 'select(."grpc.meta.client_name" == "gitlab-web")' current
```
#### Find all failed Gitaly requests
```sh
```shell
jq 'select(."grpc.code" != null and ."grpc.code" != "OK")' current
```
#### Find all requests that took longer than 30 seconds
```sh
```shell
jq 'select(."grpc.time_ms" > 30000)' current
```
#### Print top three projects by request volume and their three longest durations
```sh
```shell
jq -s -r 'map(select(."grpc.request.glProjectPath" != null and ."grpc.request.glProjectPath" != "" and ."grpc.time_ms" != null)) | group_by(."grpc.request.glProjectPath") | sort_by(-length) | limit(3; .[]) | sort_by(-."grpc.time_ms") | "CT: \(length)\tPROJECT: \(.[0]."grpc.request.glProjectPath")\tDURS: \(.[0]."grpc.time_ms"), \(.[1]."grpc.time_ms"), \(.[2]."grpc.time_ms")"' current
```

View File

@ -11,7 +11,7 @@ interact with the Freeze Period API endpoints.
## List Freeze Periods
Paginated list of Freeze Periods, sorted by `created_at`.
Paginated list of Freeze Periods, sorted by `created_at` in ascending order.
```plaintext
GET /projects/:id/freeze_periods

View File

@ -297,7 +297,7 @@ POST /projects/:id/pipeline_schedules/:pipeline_schedule_id/play
Example request:
```sh
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/42/pipeline_schedules/1/play
```

View File

@ -17,7 +17,7 @@ GET /projects/:id/remote_mirrors
Example request:
```sh
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/42/remote_mirrors'
```
@ -63,7 +63,7 @@ POST /projects/:id/remote_mirrors
Example request:
```sh
```shell
curl --request POST --data "url=https://username:token@example.com/gitlab/example.git" --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/42/remote_mirrors'
```
@ -104,7 +104,7 @@ PUT /projects/:id/remote_mirrors/:mirror_id
Example request:
```sh
```shell
curl --request PUT --data "enabled=false" --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/42/remote_mirrors/101486'
```

View File

@ -49,7 +49,7 @@ For feature flags disabled by default, if they can be used by end users:
For example, for a feature disabled by default, disabled on GitLab.com, and
not ready for production use:
````md
````markdown
# Feature Name
> - [Introduced](link-to-issue) in GitLab 12.0.
@ -93,7 +93,7 @@ For features that became enabled by default:
For example, for a feature initially deployed disabled by default, that became enabled by default, that is enabled on GitLab.com, and ready for production use:
````md
````markdown
# Feature Name
> - [Introduced](link-to-issue) in GitLab 12.0.
@ -138,7 +138,7 @@ For features enabled by default:
For example, for a feature enabled by default, enabled on GitLab.com, and ready for production use:
````md
````markdown
# Feature Name
> - [Introduced](link-to-issue) in GitLab 12.0.
@ -177,7 +177,7 @@ Once the feature is ready and the flag has been removed, clean up the
documentation. Remove the feature flag mention keeping only a note that
mentions the flag in the version history notes:
````md
````markdown
# Feature Name
> - [Introduced](link-to-issue) in GitLab 12.0.

View File

@ -79,7 +79,7 @@ change prior to merging.
If you indeed need to change a document's location, do not remove the old
document, but instead replace all of its content with the following:
```md
```markdown
---
redirect_to: '../path/to/file/index.md'
---
@ -93,7 +93,7 @@ The `redirect_to` variable supports both full and relative URLs, for example
`https://docs.gitlab.com/ee/path/to/file.html`, `../path/to/file.html`, `path/to/file.md`.
It ensures that the redirect will work for <https://docs.gitlab.com> and any `*.md` paths
will be compiled to `*.html`.
The new line underneath the frontmatter informs the user that the document
The new line underneath the front matter informs the user that the document
changed location and is useful for someone that browses that file from the repository.
For example, if you move `doc/workflow/lfs/index.md` to
@ -102,7 +102,7 @@ For example, if you move `doc/workflow/lfs/index.md` to
1. Copy `doc/workflow/lfs/index.md` to `doc/administration/lfs.md`
1. Replace the contents of `doc/workflow/lfs/index.md` with:
```md
```markdown
---
redirect_to: '../../administration/lfs.md'
---
@ -148,12 +148,12 @@ Disqus uses an identifier per page, and for <https://docs.gitlab.com>, the page
is configured to be the page URL. Therefore, when we change the document location,
we need to preserve the old URL as the same Disqus identifier.
To do that, add to the frontmatter the variable `disqus_identifier`,
using the old URL as value. For example, let's say I moved the document
To do that, add to the front matter the variable `disqus_identifier`,
using the old URL as value. For example, let's say we moved the document
available under `https://docs.gitlab.com/my-old-location/README.html` to a new location,
`https://docs.gitlab.com/my-new-location/index.html`.
Into the **new document** frontmatter add the following:
Into the **new document** front matter, we add the following:
```yaml
---
@ -298,8 +298,8 @@ To preview your changes to documentation locally, follow this
The live preview is currently enabled for the following projects:
- <https://gitlab.com/gitlab-org/gitlab>
- <https://gitlab.com/gitlab-org/gitlab-runner>
- [`gitlab`](https://gitlab.com/gitlab-org/gitlab)
- [`gitlab-runner`](https://gitlab.com/gitlab-org/gitlab-runner)
If your merge request has docs changes, you can use the manual `review-docs-deploy` job
to deploy the docs review app for your merge request.
@ -485,14 +485,14 @@ markdownlint can be used [on the command line](https://github.com/igorshubovych/
either on a single Markdown file or on all Markdown files in a project. For example, to run
markdownlint on all documentation in the [`gitlab` project](https://gitlab.com/gitlab-org/gitlab),
run the following commands from within your `gitlab` project root directory, which will
automatically detect the [`.markdownlint.json`](#markdownlint-configuration) config
automatically detect the [`.markdownlint.json`](#markdownlint-configuration) configuration
file in the root of the project, and test all files in `/doc` and its subdirectories:
```shell
markdownlint 'doc/**/*.md'
```
If you wish to use a different config file, use the `-c` flag:
If you wish to use a different configuration file, use the `-c` flag:
```shell
markdownlint -c <config-file-name> 'doc/**/*.md'
@ -506,7 +506,7 @@ such as:
- [Atom](https://atom.io/packages/linter-node-markdownlint)
It is best to use the [same configuration file](#markdownlint-configuration) as what
is in use in the four repos that are the sources for <https://docs.gitlab.com>. Each
is in use in the four repositories that are the sources for <https://docs.gitlab.com>. Each
plugin/extension has different requirements regarding the configuration file, which
is explained in each editor's docs.
@ -515,12 +515,12 @@ is explained in each editor's docs.
Each formatting issue that markdownlint checks has an associated
[rule](https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#rules).
These rules are configured in the `.markdownlint.json` files located in the root of
four repos that are the sources for <https://docs.gitlab.com>:
four repositories that are the sources for <https://docs.gitlab.com>:
- <https://gitlab.com/gitlab-org/gitlab/blob/master/.markdownlint.json>
- <https://gitlab.com/gitlab-org/gitlab-runner/blob/master/.markdownlint.json>
- <https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/.markdownlint.json>
- <https://gitlab.com/charts/gitlab/blob/master/.markdownlint.json>
- [`gitlab`](https://gitlab.com/gitlab-org/gitlab/blob/master/.markdownlint.json)
- [`gitlab-runner`](https://gitlab.com/gitlab-org/gitlab-runner/blob/master/.markdownlint.json)
- [`omnibus-gitlab`](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/.markdownlint.json)
- [`charts`](https://gitlab.com/charts/gitlab/blob/master/.markdownlint.json)
By default all rules are enabled, so the configuration file is used to disable unwanted
rules, and also to configure optional parameters for enabled rules as needed. You can
@ -550,7 +550,7 @@ You can also
[configure the text editor of your choice](https://errata-ai.github.io/vale/#local-use-by-a-single-writer)
to display the results.
Vale's test results are not currently displayed in CI, but may be displayed in the future.
Vale's test results [are displayed](#testing) in CI pipelines.
##### Disable a Vale test
@ -573,5 +573,5 @@ For more information, see [Vale's documentation](https://errata-ai.gitbook.io/va
GitLab uses [Danger](https://github.com/danger/danger) for some elements in
code review. For docs changes in merge requests, whenever a change to files under `/doc`
is made, Danger Bot leaves a comment with further instructions about the documentation
process. This is configured in the Dangerfile in the GitLab repo under
process. This is configured in the `Dangerfile` in the GitLab repository under
[/danger/documentation/](https://gitlab.com/gitlab-org/gitlab/tree/master/danger/documentation).

View File

@ -20,7 +20,7 @@ Every feature or use case document should include the following content in the f
with exceptions and details noted below and in the template included on this page.
- **Title**: Top-level heading with the feature name, or a use case name, which would start with
a verb, like Configuring, Enabling, etc.
a verb, like Configuring, Enabling, and so on.
- **Introduction**: A couple sentences about the subject matter and what's to be found
on this page. Describe what the feature or topic is, what it does, and in what context it should
be used. There is no need to add a title called "Introduction" or "Overview," because people rarely
@ -41,7 +41,7 @@ and other logical divisions such as pre- and post-deployment steps.
To start a new document, respect the file tree and file name guidelines,
as well as the style guidelines. Use the following template:
```md
```markdown
<!--Follow the Style Guide when working on this document. https://docs.gitlab.com/ee/development/documentation/styleguide.html
When done, remove all of this commented-out text, except a commented-out Troubleshooting section,
which, if empty, can be left in place to encourage future use.-->
@ -130,7 +130,7 @@ Notes:
## Help and feedback section
The "help and feedback" section (introduced by [!319](https://gitlab.com/gitlab-org/gitlab-docs/-/merge_requests/319)) displayed at the end of each document
can be omitted from the doc by adding a key into the its frontmatter:
can be omitted from the doc by adding a key into the its front matter:
```yaml
---
@ -148,7 +148,7 @@ We also have integrated the docs site with Disqus (introduced by
allowing our users to post comments.
To omit only the comments from the feedback section, use the following
key on the frontmatter:
key on the front matter:
```yaml
---
@ -159,7 +159,7 @@ comments: false
We are only hiding comments in main index pages, such as [the main documentation index](../../README.md), since its content is too broad to comment on. Before omitting Disqus,
you must check with a technical writer.
Note that once `feedback: false` is added to the frontmatter, it will automatically omit
Note that once `feedback: false` is added to the front matter, it will automatically omit
Disqus, therefore, don't add both keys to the same document.
The click events in the feedback section are tracked with Google Tag Manager. The

View File

@ -390,7 +390,7 @@ tenses, words, and phrases:
- Insert an empty line for new paragraphs.
- Insert an empty line between different markups (for example, after every paragraph, header, list, and so on). Example:
```md
```markdown
## Header
Paragraph.
@ -447,7 +447,7 @@ Only use ordered lists when their items describe a sequence of steps to follow.
Do:
```md
```markdown
These are the steps to do something:
1. First, do the first step.
@ -457,7 +457,7 @@ These are the steps to do something:
Don't:
```md
```markdown
This is a list of available features:
1. Feature 1
@ -483,7 +483,7 @@ This is a list of available features:
all with a period.
- Separate list items from explanatory text with a colon (`:`). For example:
```md
```markdown
The list is as follows:
- First item: this explains the first item.
@ -630,7 +630,7 @@ page), use the following phrases (based on the SVG icons):
## Quotes
Valid for Markdown content only, not for frontmatter entries:
Valid for Markdown content only, not for front matter entries:
- Standard quotes: double quotes (`"`). Example: "This is wrapped in double quotes".
- Quote within a quote: double quotes (`"`) wrap single quotes (`'`). Example: "I am 'quoting' something within a quote".
@ -792,7 +792,7 @@ Instead:
Example:
```md
```markdown
For more information, see the [confidential issue](../../user/project/issues/confidential_issues.md) `https://gitlab.com/gitlab-org/gitlab-foss/issues/<issue_number>`.
```
@ -908,7 +908,7 @@ Do not upload videos to the product repositories. [Link](#link-to-video) or [emb
To link out to a video, include a YouTube icon so that readers can
quickly and easily scan the page for videos before reading:
```md
```markdown
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [Video Title](link-to-video).
```
@ -1082,7 +1082,7 @@ This will ensure that the source Markdown remains readable and should help with
The following are examples of source Markdown for menu items with their published output:
```md
```markdown
1. Go to **{home}** **Project overview > Details**
1. Go to **{doc-text}** **Repository > Branches**
1. Go to **{issues}** **Issues > List**
@ -1143,7 +1143,7 @@ of users.
Weigh the costs of distracting users to whom the content is not relevant against
the cost of users missing the content if it were not expressed as a note.
```md
```markdown
NOTE: **Note:**
This is something to note.
```
@ -1155,7 +1155,7 @@ This is something to note.
### Tip
```md
```markdown
TIP: **Tip:**
This is a tip.
```
@ -1167,7 +1167,7 @@ This is a tip.
### Caution
```md
```markdown
CAUTION: **Caution:**
This is something to be cautious about.
```
@ -1179,7 +1179,7 @@ This is something to be cautious about.
### Danger
```md
```markdown
DANGER: **Danger:**
This is a breaking change, a bug, or something very important to note.
```
@ -1193,7 +1193,7 @@ This is a breaking change, a bug, or something very important to note.
For highlighting a text within a blue blockquote, use this format:
```md
```markdown
> This is a blockquote.
```
@ -1205,7 +1205,7 @@ If the text spans across multiple lines it's OK to split the line.
For multiple paragraphs, use the symbol `>` before every line:
```md
```markdown
> This is the first paragraph.
>
> This is the second paragraph.
@ -1298,14 +1298,14 @@ a helpful link back to how the feature was developed.
- If listing information for multiple version as a feature evolves, add the information to a
block-quoted bullet list. For example:
```md
```markdown
> - [Introduced](<link-to-issue>) in GitLab 11.3.
> - Enabled by default in GitLab 11.4.
```
- If a feature is moved to another tier:
```md
```markdown
> - [Introduced](<link-to-issue>) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.5.
> - [Moved](<link-to-issue>) to [GitLab Starter](https://about.gitlab.com/pricing/) in 11.8.
> - [Moved](<link-to-issue>) to GitLab Core in 12.0.
@ -1417,7 +1417,7 @@ avoid duplication, link to the special document that can be found in
[`doc/administration/restart_gitlab.md`](../../administration/restart_gitlab.md).
Usually the text will read like:
```md
```markdown
Save the file and [reconfigure GitLab](../../administration/restart_gitlab.md)
for the changes to take effect.
```
@ -1453,7 +1453,7 @@ When there is a list of steps to perform, usually that entails editing the
configuration file and reconfiguring/restarting GitLab. In such case, follow
the style below as a guide:
````md
````markdown
**For Omnibus installations**
1. Edit `/etc/gitlab/gitlab.rb`:
@ -1591,7 +1591,7 @@ You can use the following fake tokens as examples.
Use the following table headers to describe the methods. Attributes should
always be in code blocks using backticks (`` ` ``).
```md
```markdown
| Attribute | Type | Required | Description |
|:----------|:-----|:---------|:------------|
```

View File

@ -26,7 +26,7 @@ If you do not provide any arguments, it will globally query and instantiate all
<ul>
```
```js
```javascript
const droplab = new DropLab();
droplab.init();
```
@ -47,7 +47,7 @@ You can add static list items.
<ul>
```
```js
```javascript
const droplab = new DropLab();
droplab.init();
```
@ -65,7 +65,7 @@ a non-global instance of DropLab using the `DropLab.prototype.init` method.
<ul>
```
```js
```javascript
const trigger = document.getElementById('trigger');
const list = document.getElementById('list');
@ -83,7 +83,7 @@ You can also add hooks to an existing DropLab instance using `DropLab.prototype.
<ul id="list" data-dropdown><!-- ... --><ul>
```
```js
```javascript
const droplab = new DropLab();
droplab.init();
@ -114,7 +114,7 @@ for all `data-dynamic` dropdown lists tracked by that DropLab instance.
</ul>
```
```js
```javascript
const droplab = new DropLab();
droplab.init().addData([{
@ -137,7 +137,7 @@ the data as the second argument and the `id` of the trigger element as the first
</ul>
```
```js
```javascript
const droplab = new DropLab();
droplab.init().addData('trigger', [{
@ -167,7 +167,7 @@ dropdown lists, one of which is dynamic.
</div>
```
```js
```javascript
const droplab = new DropLab();
droplab.init().addData('trigger', [{
@ -224,7 +224,7 @@ Some plugins require configuration values, the config object can be passed as th
<ul id="list" data-dropdown><!-- ... --><ul>
```
```js
```javascript
const droplab = new DropLab();
const trigger = document.getElementById('trigger');
@ -249,7 +249,7 @@ droplab.init(trigger, list, [droplabAjax], {
When plugins are initialised for a droplab trigger+dropdown, DropLab will
call the plugins `init` function, so this must be implemented in the plugin.
```js
```javascript
class MyPlugin {
static init() {
this.someProp = 'someProp';

View File

@ -18,7 +18,7 @@ Add the `Ajax` object to the plugins array of a `DropLab.prototype.init` or `Dro
<ul id="list" data-dropdown><!-- ... --><ul>
```
```js
```javascript
const droplab = new DropLab();
const trigger = document.getElementById('trigger');

View File

@ -18,7 +18,7 @@ Add the `Filter` object to the plugins array of a `DropLab.prototype.init` or `D
<ul>
```
```js
```javascript
const droplab = new DropLab();
const trigger = document.getElementById('trigger');

View File

@ -23,7 +23,7 @@ You can also set the `InputSetter` config to an array of objects, which will all
<ul>
```
```js
```javascript
const droplab = new DropLab();
const trigger = document.getElementById('trigger');

View File

@ -212,7 +212,7 @@ Read more about local state management with Apollo in the [Vue Apollo documentat
When Apollo Client is used within Vuex and fetched data is stored in the Vuex store, there is no need in keeping Apollo Client cache enabled. Otherwise we would have data from the API stored in two places - Vuex store and Apollo Client cache. More to say, with Apollo default settings, a subsequent fetch from the GraphQL API could result in fetching data from Apollo cache (in the case where we have the same query and variables). To prevent this behavior, we need to disable Apollo Client cache passing a valid `fetchPolicy` option to its constructor:
```js
```javascript
import fetchPolicies from '~/graphql_shared/fetch_policy_constants';
export const gqClient = createGqClient(

View File

@ -111,7 +111,7 @@ export default {
</template>
```
```js
```javascript
// MyAwesomeComponent.spec.js
import SomeChildComponent from '~/some_child_component.vue'

View File

@ -131,7 +131,7 @@ You can mark that content for translation with:
In JavaScript we added the `__()` (double underscore parenthesis) function that
you can import from the `~/locale` file. For instance:
```js
```javascript
import { __ } from '~/locale';
const label = __('Subscribe');
```
@ -167,7 +167,7 @@ For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make s
- In JavaScript (when Vue cannot be used):
```js
```javascript
import { __, sprintf } from '~/locale';
sprintf(__('Hello %{username}'), { username: 'Joe' }); // => 'Hello Joe'
@ -180,7 +180,7 @@ For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make s
escape any interpolated dynamic values yourself, for instance using
`escape` from `lodash`.
```js
```javascript
import { escape } from 'lodash';
import { __, sprintf } from '~/locale';
@ -220,14 +220,14 @@ For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make s
- In JavaScript:
```js
```javascript
n__('Apple', 'Apples', 3)
// => 'Apples'
```
Using interpolation:
```js
```javascript
n__('Last day', 'Last %d days', x)
// => When x == 1: 'Last day'
// => When x == 2: 'Last 2 days'
@ -274,7 +274,7 @@ Namespaces should be PascalCase.
- In JavaScript:
```js
```javascript
s__('OpenedNDaysAgo|Opened')
```
@ -285,7 +285,7 @@ guidelines for more details](translation.md#namespaced-strings).
- In JavaScript:
```js
```javascript
import { createDateTimeFormat } from '~/locale';
const dateFormat = createDateTimeFormat({ year: 'numeric', month: 'long', day: 'numeric' });
@ -372,7 +372,7 @@ structure is the same in all languages.
For instance, the following:
```js
```javascript
{{ s__("mrWidget|Set by") }}
{{ author.name }}
{{ s__("mrWidget|to be merged automatically when the pipeline succeeds") }}
@ -380,7 +380,7 @@ For instance, the following:
should be externalized as follows:
```js
```javascript
{{ sprintf(s__("mrWidget|Set by %{author} to be merged automatically when the pipeline succeeds"), { author: author.name }) }}
```
@ -439,7 +439,7 @@ This also applies when using links in between translated sentences, otherwise th
- In JavaScript (when Vue cannot be used), instead of:
```js
```javascript
{{
sprintf(s__("ClusterIntegration|Learn more about %{link}"), {
link: '<a href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" rel="noopener noreferrer">zones</a>'
@ -449,7 +449,7 @@ This also applies when using links in between translated sentences, otherwise th
Set the link starting and ending HTML fragments as placeholders like so:
```js
```javascript
{{
sprintf(s__("ClusterIntegration|Learn more about %{linkStart}zones%{linkEnd}"), {
linkStart: '<a href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" rel="noopener noreferrer">',

View File

@ -51,7 +51,7 @@ or `db/post_migrate`, so if there are any migrations you don't want to
commit to the schema, rename or remove them. If your branch is not
targetting `master` you can set the `TARGET` environment variable.
```sh
```shell
# Regenerate schema against `master`
scripts/regenerate-schema

View File

@ -13,7 +13,7 @@ within the GitLab project.
## Usage
```js
```javascript
import dirtySubmitFactory from './dirty_submit/dirty_submit_form';
new DirtySubmitForm(document.querySelector('form'));

View File

@ -184,7 +184,7 @@ Reference pipeline: <https://gitlab.com/gitlab-org/gitlab/pipelines/135236627>
```mermaid
graph LR
subgraph "No needed jobs";
1-1["danger-review (5.3 minutes)"];
1-1["danger-review (3.5 minutes)"];
click 1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8100542&udv=0"
1-50["docs lint (6.75 minutes)"];
click 1-50 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356757&udv=0"
@ -200,9 +200,9 @@ graph RL;
classDef criticalPath fill:#f66;
subgraph "No needed jobs";
1-1["danger-review (5.3 minutes)"];
1-1["danger-review (3.5 minutes)"];
click 1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8100542&udv=0"
1-2["build-qa-image (4.4 minutes)"];
1-2["build-qa-image (3.4 minutes)"];
click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0"
1-3["compile-assets pull-cache (9.06 minutes)"];
click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914317&udv=0"
@ -210,7 +210,7 @@ graph RL;
click 1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356616&udv=0"
1-5["gitlab:assets:compile pull-cache (22 minutes)"];
click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0"
1-6["setup-test-env (9.6 minutes)"];
1-6["setup-test-env (8.22 minutes)"];
click 1-6 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914315&udv=0"
1-7["review-stop-failed-deployment"];
1-8["dependency_scanning"];
@ -250,7 +250,7 @@ graph RL;
click 2_2-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7910154&udv=0"
2_2-4["memory-on-boot (7.19 minutes)"];
click 2_2-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356727&udv=0"
2_2-5["webpack-dev-server (7.62 minutes)"];
2_2-5["webpack-dev-server (6.1 minutes)"];
click 2_2-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8404303&udv=0"
subgraph "Needs `setup-test-env` & `compile-assets`";
2_2-1 & 2_2-2 & 2_2-4 & 2_2-5 --> 1-6 & 1-3;
@ -275,28 +275,28 @@ graph RL;
click 2_5-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations"
end
3_1-1["jest (11.2 minutes)"];
3_1-1["jest (15 minutes)"];
class 3_1-1 criticalPath;
click 3_1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914204&udv=0"
3_1-2["karma (9.18 minutes)"];
3_1-2["karma (8 minutes)"];
click 3_1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914200&udv=0"
3_1-3["jest-as-if-foss (14.8 minutes)"];
3_1-3["jest-as-if-foss (19.7 minutes)"];
click 3_1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914205&udv=0"
3_1-4["karma-as-if-foss (8.25 minutes)"];
3_1-4["karma-as-if-foss (7.5 minutes)"];
click 3_1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914203&udv=0"
subgraph "Needs `frontend-fixtures`";
3_1-1 & 3_1-2 --> 2_2-2;
3_1-3 & 3_1-4 --> 2_2-3;
end
3_2-1["rspec:coverage (7.67 minutes)"];
3_2-1["rspec:coverage (6.5 minutes)"];
subgraph "Depends on `rspec` jobs";
3_2-1 -.->|"(don't use needs because of limitations)"| 2_5-1;
class 3_2-1 criticalPath;
click 3_2-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7248745&udv=0"
end
4_1-1["coverage-frontend (5.39 minutes)"];
4_1-1["coverage-frontend (3.6 minutes)"];
subgraph "Needs `jest`";
4_1-1 --> 3_1-1;
class 4_1-1 criticalPath;
@ -313,9 +313,9 @@ graph RL;
classDef criticalPath fill:#f66;
subgraph "No needed jobs";
1-1["danger-review (5.3 minutes)"];
1-1["danger-review (3.5 minutes)"];
click 1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8100542&udv=0"
1-2["build-qa-image (4.4 minutes)"];
1-2["build-qa-image (3.4 minutes)"];
click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0"
1-3["compile-assets pull-cache (9.06 minutes)"];
click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914317&udv=0"
@ -323,7 +323,7 @@ graph RL;
click 1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356616&udv=0"
1-5["gitlab:assets:compile pull-cache (22 minutes)"];
click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0"
1-6["setup-test-env (9.6 minutes)"];
1-6["setup-test-env (8.22 minutes)"];
click 1-6 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914315&udv=0"
1-7["review-stop-failed-deployment"];
1-8["dependency_scanning"];
@ -364,7 +364,7 @@ graph RL;
click 2_2-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7910154&udv=0"
2_2-4["memory-on-boot (7.19 minutes)"];
click 2_2-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356727&udv=0"
2_2-5["webpack-dev-server (7.62 minutes)"];
2_2-5["webpack-dev-server (6.1 minutes)"];
click 2_2-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8404303&udv=0"
subgraph "Needs `setup-test-env` & `compile-assets`";
2_2-1 & 2_2-2 & 2_2-4 & 2_2-5 --> 1-6 & 1-3;
@ -397,28 +397,28 @@ graph RL;
click 2_6-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914314&udv=0"
end
3_1-1["jest (11.2 minutes)"];
3_1-1["jest (15 minutes)"];
class 3_1-1 criticalPath;
click 3_1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914204&udv=0"
3_1-2["karma (9.18 minutes)"];
3_1-2["karma (8 minutes)"];
click 3_1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914200&udv=0"
3_1-3["jest-as-if-foss (14.8 minutes)"];
3_1-3["jest-as-if-foss (19.7 minutes)"];
click 3_1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914205&udv=0"
3_1-4["karma-as-if-foss (8.25 minutes)"];
3_1-4["karma-as-if-foss (7.5 minutes)"];
click 3_1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914203&udv=0"
subgraph "Needs `frontend-fixtures`";
3_1-1 & 3_1-3 --> 2_2-2;
3_1-2 & 3_1-4 --> 2_2-3;
end
3_2-1["rspec:coverage (7.67 minutes)"];
3_2-1["rspec:coverage (6.5 minutes)"];
subgraph "Depends on `rspec` jobs";
3_2-1 -.->|"(don't use needs because of limitations)"| 2_5-1;
class 3_2-1 criticalPath;
click 3_2-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7248745&udv=0"
end
4_1-1["coverage-frontend (5.39 minutes)"];
4_1-1["coverage-frontend (3.6 minutes)"];
subgraph "Needs `jest`";
4_1-1 --> 3_1-1;
class 4_1-1 criticalPath;
@ -432,9 +432,9 @@ graph RL;
click 3_3-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6721130&udv=0"
end
4_2-1["review-qa-smoke (7.29 minutes)"];
4_2-1["review-qa-smoke (8 minutes)"];
click 4_2-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6729805&udv=0"
4_2-2["review-performance (3.83 minutes)"];
4_2-2["review-performance (4 minutes)"];
click 4_2-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356817&udv=0"
4_2-3["dast (18 minutes)"];
click 4_2-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356819&udv=0"
@ -453,9 +453,9 @@ graph RL;
classDef criticalPath fill:#f66;
subgraph "No needed jobs";
1-1["danger-review (5.3 minutes)"];
1-1["danger-review (3.5 minutes)"];
click 1-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8100542&udv=0"
1-2["build-qa-image (4.4 minutes)"];
1-2["build-qa-image (3.4 minutes)"];
click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0"
1-3["compile-assets pull-cache (9.06 minutes)"];
click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914317&udv=0"
@ -463,7 +463,7 @@ graph RL;
click 1-4 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356616&udv=0"
1-5["gitlab:assets:compile pull-cache (22 minutes)"];
click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0"
1-6["setup-test-env (9.6 minutes)"];
1-6["setup-test-env (8.22 minutes)"];
click 1-6 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914315&udv=0"
1-7["review-stop-failed-deployment"];
1-8["dependency_scanning"];

View File

@ -98,7 +98,7 @@ If it's not possible to follow the above method, the images can be transferred m
#### Example image packager script
```sh
```shell
#!/bin/bash
set -ux
@ -120,7 +120,7 @@ done
This example loads the images from a bastion host to an offline host. In certain configurations,
physical media may be needed for such a transfer:
```sh
```shell
#!/bin/bash
set -ux

View File

@ -39,7 +39,7 @@ being modified after the database dump is created.
1. Get the Kubernetes namespace for the environment. It typically looks like `<project-name>-<project-id>-<environment>`.
In our example, the namespace is called `minimal-ruby-app-4349298-production`.
```sh
```shell
$ kubectl get ns
NAME STATUS AGE
@ -48,13 +48,13 @@ being modified after the database dump is created.
1. For ease of use, export the namespace name:
```sh
```shell
export APP_NAMESPACE=minimal-ruby-app-4349298-production
```
1. Get the deployment name for your application with the following command. In our example, the deployment name is `production`.
```sh
```shell
$ kubectl get deployment --namespace "$APP_NAMESPACE"
NAME READY UP-TO-DATE AVAILABLE AGE
production 2/2 2 2 7d21h
@ -64,7 +64,7 @@ being modified after the database dump is created.
1. To prevent the database from being modified, set replicas to 0 for the deployment with the following command.
We use the deployment name from the previous step (`deployments/<DEPLOYMENT_NAME>`).
```sh
```shell
$ kubectl scale --replicas=0 deployments/production --namespace "$APP_NAMESPACE"
deployment.extensions/production scaled
```
@ -75,7 +75,7 @@ being modified after the database dump is created.
1. Get the service name for PostgreSQL. The name of the service should end with `-postgres`. In our example the service name is `production-postgres`.
```sh
```shell
$ kubectl get svc --namespace "$APP_NAMESPACE"
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
production-auto-deploy ClusterIP 10.30.13.90 <none> 5000/TCP 7d14h
@ -84,7 +84,7 @@ being modified after the database dump is created.
1. Get the pod name for PostgreSQL with the following command. In our example, the pod name is `production-postgres-5db86568d7-qxlxv`.
```sh
```shell
$ kubectl get pod --namespace "$APP_NAMESPACE" -l app=production-postgres
NAME READY STATUS RESTARTS AGE
production-postgres-5db86568d7-qxlxv 1/1 Running 0 7d14h
@ -92,7 +92,7 @@ being modified after the database dump is created.
1. Connect to the pod with:
```sh
```shell
kubectl exec -it production-postgres-5db86568d7-qxlxv --namespace "$APP_NAMESPACE" bash
```
@ -104,7 +104,7 @@ being modified after the database dump is created.
- You will be asked for the database password, the default is `testing-password`.
```sh
```shell
## Format is:
# pg_dump -h SERVICE_NAME -U USERNAME DATABASE_NAME > /tmp/backup.sql
@ -115,7 +115,7 @@ being modified after the database dump is created.
1. Download the dump file with the following command:
```sh
```shell
kubectl cp --namespace "$APP_NAMESPACE" production-postgres-5db86568d7-qxlxv:/tmp/backup.sql backup.sql
```
@ -131,7 +131,7 @@ deleted causing the persistent volumes to be deleted as well.
You can verify this by using the following command:
```sh
```shell
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-0da80c08-5239-11ea-9c8d-42010a8e0096 8Gi RWO Delete Bound minimal-ruby-app-4349298-staging/staging-postgres standard 7d22h
@ -145,7 +145,7 @@ interested in keeping the volumes for the staging and production of the
`minimal-ruby-app-4349298` application, the volume names here are
`pvc-0da80c08-5239-11ea-9c8d-42010a8e0096` and `pvc-9085e3d3-5239-11ea-9c8d-42010a8e0096`:
```sh
```shell
$ kubectl patch pv pvc-0da80c08-5239-11ea-9c8d-42010a8e0096 -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
persistentvolume/pvc-0da80c08-5239-11ea-9c8d-42010a8e0096 patched
$ kubectl patch pv pvc-9085e3d3-5239-11ea-9c8d-42010a8e0096 -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
@ -192,7 +192,7 @@ TIP: **Tip:** You can also
1. Get the pod name for the new PostgreSQL, in our example, the pod name is
`production-postgresql-0`:
```sh
```shell
$ kubectl get pod --namespace "$APP_NAMESPACE" -l app=postgresql
NAME READY STATUS RESTARTS AGE
production-postgresql-0 1/1 Running 0 19m
@ -200,13 +200,13 @@ TIP: **Tip:** You can also
1. Copy the dump file from the backup steps to the pod:
```sh
```shell
kubectl cp --namespace "$APP_NAMESPACE" backup.sql production-postgresql-0:/tmp/backup.sql
```
1. Connect to the pod:
```sh
```shell
kubectl exec -it production-postgresql-0 --namespace "$APP_NAMESPACE" bash
```
@ -216,7 +216,7 @@ TIP: **Tip:** You can also
- `USERNAME` is the username you have configured for PostgreSQL. The default is `user`.
- `DATABASE_NAME` is usually the environment name.
```sh
```shell
## Format is:
# psql -U USERNAME -d DATABASE_NAME < /tmp/backup.sql

View File

@ -228,7 +228,7 @@ To make PlantUML available in GitLab, a GitLab administrator needs to enable it
> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#emoji).
```md
```markdown
Sometimes you want to :monkey: around a bit and add some :star2: to your :speech_balloon:. Well we have a gift for you:
:zap: You can use emoji anywhere GFM is supported. :v:
@ -804,7 +804,7 @@ but_emphasis is_desired _here_
If you wish to emphasize only a part of a word, it can still be done with asterisks:
```md
```markdown
perform*complicated*task
do*this*and*do*that*and*another thing
@ -976,7 +976,7 @@ Do not change to a reference style link.
Image tags that link to files with a video extension are automatically converted to
a video player. The valid video extensions are `.mp4`, `.m4v`, `.mov`, `.webm`, and `.ogv`:
```md
```markdown
Here's a sample video:
![Sample Video](img/markdown_video.mp4)
@ -993,7 +993,7 @@ Here's a sample video:
Similar to videos, link tags for files with an audio extension are automatically converted to
an audio player. The valid audio extensions are `.mp3`, `.oga`, `.ogg`, `.spx`, and `.wav`:
```md
```markdown
Here's a sample audio clip:
![Sample Audio](img/markdown_audio.mp3)
@ -1275,7 +1275,7 @@ number, and count up from there.
Examples:
```md
```markdown
1. First ordered list item
2. Another item
- Unordered sub-list.
@ -1302,7 +1302,7 @@ See https://docs.gitlab.com/ee/development/documentation/styleguide.html#lists
For an unordered list, add a `-`, `*` or `+`, followed by a space, at the start of
each line for unordered lists, but you should not use a mix of them.
```md
```markdown
Unordered lists can:
- use

View File

@ -137,7 +137,7 @@ The minimum scope needed for both of them is `read_registry`.
Example of using a token:
```sh
```shell
docker login registry.example.com -u <username> -p <token>
```
@ -206,7 +206,7 @@ Available for all projects, though more suitable for public ones:
your Docker images and has read/write access to the Registry. This is ephemeral,
so it's only valid for one job. You can use the following example as-is:
```sh
```shell
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
```
@ -221,7 +221,7 @@ For private and internal projects:
Replace the `<username>` and `<access_token>` in the following example:
```sh
```shell
docker login -u <username> -p <access_token> $CI_REGISTRY
```
@ -231,7 +231,7 @@ For private and internal projects:
Once created, you can use the special environment variables, and GitLab CI/CD
will fill them in for you. You can use the following example as-is:
```sh
```shell
docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY
```

View File

@ -39,6 +39,26 @@ templates of the default branch will be taken into account.
Create a new Markdown (`.md`) file inside the `.gitlab/issue_templates/`
directory in your repository. Commit and push to your default branch.
To create a Markdown file:
1. Click the `+` button next to `master` and click **New file**.
1. Add the name of your issue template to the **File name** text field next to `master`.
Make sure words are separated with underscores and that your file has the `.md` extension, for
example `feature_request.md`.
1. Commit and push to your default branch.
If you don't have a `.gitlab/issue_templates` directory in your repository, you'll need to create it.
To create the `.gitlab/issue_templates` directory:
1. Click the `+` button next to `master` and select **New directory**.
1. Name this new directory `.gitlab` and commit to your default branch.
1. Click the `+` button next to `master` again and select **New directory**.This time, n
1. Name your directory `issue_templates` and commit to your default branch.
To check if this has worked correctly, [create a new issue](./issues/managing_issues.md#create-a-new-issue)
and see if you can choose a description template.
## Creating merge request templates
Similarly to issue templates, create a new Markdown (`.md`) file inside the

View File

@ -183,7 +183,7 @@ but it will not close automatically.
If the issue is in a different repository than the MR, add the full URL for the issue(s):
```md
```markdown
Closes #4, #6, and https://gitlab.com/<username>/<projectname>/issues/<xxx>
```

View File

@ -252,6 +252,9 @@ generate Release Evidence for an existing release. Because of this, [each releas
can have multiple Release Evidence snapshots. You can view the Release Evidence and
its details on the Release page.
NOTE: **Note:**
When the issue tracker is disabled, release evidence [is not collected](https://gitlab.com/gitlab-org/gitlab/-/issues/208397).
Release Evidence is stored as a JSON object, so you can compare evidence by using
commonly-available tools.
@ -371,7 +374,7 @@ freeze periods, all will apply, and should they overlap, the freeze covers the
complete overlapped period.
During pipeline processing, GitLab CI creates an environment variable named
`$CI_ENVIRONMENT_FROZEN` if the currently executing job is within a
`$CI_DEPLOY_FREEZE` if the currently executing job is within a
Freeze Period.
To take advantage of this variable, create a `rules` entry in your
@ -384,7 +387,7 @@ deploy_to_production:
stage: deploy
script: deploy_to_prod.sh
rules:
- if: $CI_ENVIRONMENT_FROZEN == null
- if: $CI_DEPLOY_FREEZE == null
```
<!-- ## Troubleshooting

View File

@ -47,7 +47,7 @@ and some of them generate keys for free.
To take advantage of X.509 signing, you will need Git 2.19.0 or later. You can
check your Git version with:
```sh
```shell
git --version
```
@ -57,7 +57,7 @@ If you have the correct version, you can proceed to configure Git.
Configure Git to use your key for signing:
```sh
```shell
signingkey = $( gpgsm --list-secret-keys | egrep '(key usage|ID)' | grep -B 1 digitalSignature | awk '/ID/ {print $2}' )
git config --global user.signingkey $signingkey
git config --global gpg.format x509
@ -71,7 +71,7 @@ installer or via `brew install smimesign` on MacOS.
Get the ID of your certificate with `smimesign --list-keys` and set your
signingkey `git config --global user.signingkey ID`, then configure X.509:
```sh
```shell
git config --global gpg.x509.program smimesign
git config --global gpg.format x509
```
@ -83,7 +83,7 @@ can start signing your commits:
1. Commit like you used to, the only difference is the addition of the `-S` flag:
```sh
```shell
git commit -S -m "feat: x509 signed commits"
```
@ -92,7 +92,7 @@ can start signing your commits:
If you don't want to type the `-S` flag every time you commit, you can tell Git
to sign your commits automatically:
```sh
```shell
git config --global commit.gpgsign true
```
@ -100,7 +100,7 @@ git config --global commit.gpgsign true
To verify that a commit is signed, you can use the `--show-signature` flag:
```sh
```shell
git log --show-signature
```
@ -111,7 +111,7 @@ can start signing your tags:
1. Tag like you used to, the only difference is the addition of the `-s` flag:
```sh
```shell
git tag -s v1.1.1 -m "My signed tag"
```
@ -120,7 +120,7 @@ can start signing your tags:
If you don't want to type the `-s` flag every time you tag, you can tell Git
to sign your tags automatically:
```sh
```shell
git config --global tag.gpgsign true
```
@ -128,6 +128,6 @@ git config --global tag.gpgsign true
To verify that a tag is signed, you can use the `--verify` flag:
```sh
```shell
git tag --verify v1.1.1
```

View File

@ -0,0 +1,70 @@
# frozen_string_literal: true
require 'spec_helper'
describe Admin::Ci::VariablesController do
let_it_be(:variable) { create(:ci_instance_variable) }
before do
sign_in(user)
end
describe 'GET #show' do
subject do
get :show, params: {}, format: :json
end
context 'when signed in as admin' do
let(:user) { create(:admin) }
include_examples 'GET #show lists all variables'
end
context 'when signed in as regular user' do
let(:user) { create(:user) }
it 'returns 404' do
subject
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
describe 'PATCH #update' do
subject do
patch :update,
params: {
variables_attributes: variables_attributes
},
format: :json
end
context 'when signed in as admin' do
let(:user) { create(:admin) }
include_examples 'PATCH #update updates variables' do
let(:variables_scope) { Ci::InstanceVariable.all }
let(:file_variables_scope) { variables_scope.file }
end
end
context 'when signed in as regular user' do
let(:user) { create(:user) }
let(:variables_attributes) do
[{
id: variable.id,
key: variable.key,
secret_value: 'new value'
}]
end
it 'returns 404' do
subject
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
end

View File

@ -111,26 +111,6 @@ RSpec.describe Release do
end
end
describe '#notify_new_release' do
context 'when a release is created' do
it 'instantiates NewReleaseWorker to send notifications' do
expect(NewReleaseWorker).to receive(:perform_async)
create(:release)
end
end
context 'when a release is updated' do
let!(:release) { create(:release) }
it 'does not send any new notification' do
expect(NewReleaseWorker).not_to receive(:perform_async)
release.update!(description: 'new description')
end
end
end
describe '#name' do
context 'name is nil' do
before do

View File

@ -0,0 +1,230 @@
# frozen_string_literal: true
require 'spec_helper'
describe Ci::UpdateInstanceVariablesService do
let(:params) { { variables_attributes: variables_attributes } }
subject { described_class.new(params) }
describe '#execute' do
context 'without variables' do
let(:variables_attributes) { [] }
it { expect(subject.execute).to be_truthy }
end
context 'with insert only variables' do
let(:variables_attributes) do
[
{ key: 'var_a', secret_value: 'dummy_value_for_a', protected: true },
{ key: 'var_b', secret_value: 'dummy_value_for_b', protected: false }
]
end
it { expect(subject.execute).to be_truthy }
it 'persists all the records' do
expect { subject.execute }
.to change { Ci::InstanceVariable.count }
.by variables_attributes.size
end
it 'persists attributes' do
subject.execute
expect(Ci::InstanceVariable.all).to contain_exactly(
have_attributes(key: 'var_a', secret_value: 'dummy_value_for_a', protected: true),
have_attributes(key: 'var_b', secret_value: 'dummy_value_for_b', protected: false)
)
end
end
context 'with update only variables' do
let!(:var_a) { create(:ci_instance_variable) }
let!(:var_b) { create(:ci_instance_variable, protected: false) }
let(:variables_attributes) do
[
{
id: var_a.id,
key: var_a.key,
secret_value: 'new_dummy_value_for_a',
protected: var_a.protected?.to_s
},
{
id: var_b.id,
key: 'var_b_key',
secret_value: 'new_dummy_value_for_b',
protected: 'true'
}
]
end
it { expect(subject.execute).to be_truthy }
it 'does not change the count' do
expect { subject.execute }
.not_to change { Ci::InstanceVariable.count }
end
it 'updates the records in place', :aggregate_failures do
subject.execute
expect(var_a.reload).to have_attributes(secret_value: 'new_dummy_value_for_a')
expect(var_b.reload).to have_attributes(
key: 'var_b_key', secret_value: 'new_dummy_value_for_b', protected: true)
end
end
context 'with insert and update variables' do
let!(:var_a) { create(:ci_instance_variable) }
let(:variables_attributes) do
[
{
id: var_a.id,
key: var_a.key,
secret_value: 'new_dummy_value_for_a',
protected: var_a.protected?.to_s
},
{
key: 'var_b',
secret_value: 'dummy_value_for_b',
protected: true
}
]
end
it { expect(subject.execute).to be_truthy }
it 'inserts only one record' do
expect { subject.execute }
.to change { Ci::InstanceVariable.count }.by 1
end
it 'persists all the records', :aggregate_failures do
subject.execute
var_b = Ci::InstanceVariable.find_by(key: 'var_b')
expect(var_a.reload.secret_value).to eq('new_dummy_value_for_a')
expect(var_b.secret_value).to eq('dummy_value_for_b')
end
end
context 'with insert, update, and destroy variables' do
let!(:var_a) { create(:ci_instance_variable) }
let!(:var_b) { create(:ci_instance_variable) }
let(:variables_attributes) do
[
{
id: var_a.id,
key: var_a.key,
secret_value: 'new_dummy_value_for_a',
protected: var_a.protected?.to_s
},
{
id: var_b.id,
key: var_b.key,
secret_value: 'dummy_value_for_b',
protected: var_b.protected?.to_s,
'_destroy' => 'true'
},
{
key: 'var_c',
secret_value: 'dummy_value_for_c',
protected: true
}
]
end
it { expect(subject.execute).to be_truthy }
it 'persists all the records', :aggregate_failures do
subject.execute
var_c = Ci::InstanceVariable.find_by(key: 'var_c')
expect(var_a.reload.secret_value).to eq('new_dummy_value_for_a')
expect { var_b.reload }.to raise_error(ActiveRecord::RecordNotFound)
expect(var_c.secret_value).to eq('dummy_value_for_c')
end
end
context 'with invalid variables' do
let!(:var_a) { create(:ci_instance_variable, secret_value: 'dummy_value_for_a') }
let(:variables_attributes) do
[
{
key: '...?',
secret_value: 'nice_value'
},
{
id: var_a.id,
key: var_a.key,
secret_value: 'new_dummy_value_for_a',
protected: var_a.protected?.to_s
},
{
key: var_a.key,
secret_value: 'other_value'
}
]
end
it { expect(subject.execute).to be_falsey }
it 'does not insert any records' do
expect { subject.execute }
.not_to change { Ci::InstanceVariable.count }
end
it 'does not update existing records' do
subject.execute
expect(var_a.reload.secret_value).to eq('dummy_value_for_a')
end
it 'returns errors' do
subject.execute
expect(subject.errors).to match_array(
[
"Key (#{var_a.key}) has already been taken",
"Key can contain only letters, digits and '_'."
])
end
end
context 'when deleting non existing variables' do
let(:variables_attributes) do
[
{
id: 'some-id',
key: 'some_key',
secret_value: 'other_value',
'_destroy' => 'true'
}
]
end
it { expect { subject.execute }.to raise_error(ActiveRecord::RecordNotFound) }
end
context 'when updating non existing variables' do
let(:variables_attributes) do
[
{
id: 'some-id',
key: 'some_key',
secret_value: 'other_value'
}
]
end
it { expect { subject.execute }.to raise_error(ActiveRecord::RecordNotFound) }
end
end
end

View File

@ -762,7 +762,7 @@ describe NotificationService, :mailer do
end
end
describe '#send_new_release_notifications', :deliver_mails_inline, :sidekiq_inline do
describe '#send_new_release_notifications', :deliver_mails_inline do
context 'when recipients for a new release exist' do
let(:release) { create(:release) }
@ -774,7 +774,7 @@ describe NotificationService, :mailer do
recipient_2 = NotificationRecipient.new(user_2, :custom, custom_action: :new_release)
allow(NotificationRecipients::BuildService).to receive(:build_new_release_recipients).and_return([recipient_1, recipient_2])
release
notification.send_new_release_notifications(release)
should_email(user_1)
should_email(user_2)

View File

@ -20,6 +20,8 @@ describe Releases::CreateService do
describe '#execute' do
shared_examples 'a successful release creation' do
it 'creates a new release' do
expected_job_count = MailScheduler::NotificationServiceWorker.jobs.size + 1
result = service.execute
expect(project.releases.count).to eq(1)
@ -30,6 +32,7 @@ describe Releases::CreateService do
expect(result[:release].name).to eq(name)
expect(result[:release].author).to eq(user)
expect(result[:release].sha).to eq(tag_sha)
expect(MailScheduler::NotificationServiceWorker.jobs.size).to eq(expected_job_count)
end
end

View File

@ -27,6 +27,9 @@ RSpec.shared_examples 'PATCH #update updates variables' do
protected: 'false' }
end
let(:variables_scope) { owner.variables }
let(:file_variables_scope) { owner.variables.file }
context 'with invalid new variable parameters' do
let(:variables_attributes) do
[
@ -40,7 +43,7 @@ RSpec.shared_examples 'PATCH #update updates variables' do
end
it 'does not create the new variable' do
expect { subject }.not_to change { owner.variables.count }
expect { subject }.not_to change { variables_scope.count }
end
it 'returns a bad request response' do
@ -63,7 +66,7 @@ RSpec.shared_examples 'PATCH #update updates variables' do
end
it 'does not create the new variable' do
expect { subject }.not_to change { owner.variables.count }
expect { subject }.not_to change { variables_scope.count }
end
it 'returns a bad request response' do
@ -86,7 +89,7 @@ RSpec.shared_examples 'PATCH #update updates variables' do
end
it 'creates the new variable' do
expect { subject }.to change { owner.variables.count }.by(1)
expect { subject }.to change { variables_scope.count }.by(1)
end
it 'returns a successful response' do
@ -106,7 +109,7 @@ RSpec.shared_examples 'PATCH #update updates variables' do
let(:variables_attributes) { [variable_attributes.merge(_destroy: 'true')] }
it 'destroys the variable' do
expect { subject }.to change { owner.variables.count }.by(-1)
expect { subject }.to change { variables_scope.count }.by(-1)
expect { variable.reload }.to raise_error ActiveRecord::RecordNotFound
end
@ -123,6 +126,18 @@ RSpec.shared_examples 'PATCH #update updates variables' do
end
end
context 'with missing variable' do
let(:variables_attributes) do
[variable_attributes.merge(_destroy: 'true', id: 'some-id')]
end
it 'returns not found response' do
subject
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'for variables of type file' do
let(:variables_attributes) do
[
@ -131,7 +146,7 @@ RSpec.shared_examples 'PATCH #update updates variables' do
end
it 'creates new variable of type file' do
expect { subject }.to change { owner.variables.file.count }.by(1)
expect { subject }.to change { file_variables_scope.count }.by(1)
end
end
end

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true
# TODO: Worker can be removed in 13.2:
# https://gitlab.com/gitlab-org/gitlab/-/issues/218231
require 'spec_helper'
describe NewReleaseWorker do