summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/autosave.js13
-rw-r--r--app/assets/javascripts/snippets/components/snippet_blob_view.vue1
-rw-r--r--app/assets/javascripts/static_site_editor/index.js6
-rw-r--r--app/controllers/projects/refs_controller.rb2
-rw-r--r--app/controllers/projects/tree_controller.rb2
-rw-r--r--app/models/resource_milestone_event.rb4
-rw-r--r--app/services/issuable/clone/attributes_rewriter.rb33
-rw-r--r--changelogs/unreleased/add-ops-strategies-user-lists-table.yml5
-rw-r--r--changelogs/unreleased/dmishunov-clone-btn-margin.yml5
-rw-r--r--db/migrate/20200422213749_create_operations_strategies_user_lists.rb14
-rw-r--r--db/structure.sql31
-rw-r--r--doc/administration/geo/replication/updating_the_geo_nodes.md1
-rw-r--r--doc/administration/uploads.md18
-rw-r--r--doc/api/issues.md6
-rw-r--r--doc/install/installation.md26
-rw-r--r--doc/integration/omniauth.md2
-rw-r--r--doc/user/packages/index.md1
-rw-r--r--doc/user/packages/npm_registry/index.md8
-rw-r--r--doc/user/project/file_lock.md3
-rw-r--r--doc/user/project/issues/due_dates.md5
-rw-r--r--lib/gitlab/static_site_editor/config.rb2
-rw-r--r--locale/gitlab.pot14
-rw-r--r--package.json2
-rw-r--r--spec/frontend/autosave_spec.js90
-rw-r--r--spec/lib/gitlab/static_site_editor/config_spec.rb12
-rw-r--r--spec/models/resource_milestone_event_spec.rb17
-rw-r--r--spec/requests/api/terraform/state_spec.rb16
-rw-r--r--spec/services/issuable/clone/attributes_rewriter_spec.rb6
-rw-r--r--spec/support/unicorn.rb27
-rw-r--r--yarn.lock8
30 files changed, 320 insertions, 60 deletions
diff --git a/app/assets/javascripts/autosave.js b/app/assets/javascripts/autosave.js
index 07d79ea1c70..5f50fcc112e 100644
--- a/app/assets/javascripts/autosave.js
+++ b/app/assets/javascripts/autosave.js
@@ -3,7 +3,7 @@
import AccessorUtilities from './lib/utils/accessor';
export default class Autosave {
- constructor(field, key, fallbackKey) {
+ constructor(field, key, fallbackKey, lockVersion) {
this.field = field;
this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
@@ -12,6 +12,8 @@ export default class Autosave {
}
this.key = `autosave/${key}`;
this.fallbackKey = fallbackKey;
+ this.lockVersionKey = `${this.key}/lockVersion`;
+ this.lockVersion = lockVersion;
this.field.data('autosave', this);
this.restore();
this.field.on('input', () => this.save());
@@ -40,6 +42,11 @@ export default class Autosave {
}
}
+ getSavedLockVersion() {
+ if (!this.isLocalStorageAvailable) return;
+ return window.localStorage.getItem(this.lockVersionKey);
+ }
+
save() {
if (!this.field.length) return;
@@ -49,6 +56,9 @@ export default class Autosave {
if (this.fallbackKey) {
window.localStorage.setItem(this.fallbackKey, text);
}
+ if (this.lockVersion !== undefined) {
+ window.localStorage.setItem(this.lockVersionKey, this.lockVersion);
+ }
return window.localStorage.setItem(this.key, text);
}
@@ -58,6 +68,7 @@ export default class Autosave {
reset() {
if (!this.isLocalStorageAvailable) return;
+ window.localStorage.removeItem(this.lockVersionKey);
window.localStorage.removeItem(this.fallbackKey);
return window.localStorage.removeItem(this.key);
}
diff --git a/app/assets/javascripts/snippets/components/snippet_blob_view.vue b/app/assets/javascripts/snippets/components/snippet_blob_view.vue
index 02a0fc7686d..d615eaadb78 100644
--- a/app/assets/javascripts/snippets/components/snippet_blob_view.vue
+++ b/app/assets/javascripts/snippets/components/snippet_blob_view.vue
@@ -75,6 +75,7 @@ export default {
<template #actions>
<clone-dropdown-button
v-if="canBeCloned"
+ class="mr-2"
:ssh-link="snippet.sshUrlToRepo"
:http-link="snippet.httpUrlToRepo"
/>
diff --git a/app/assets/javascripts/static_site_editor/index.js b/app/assets/javascripts/static_site_editor/index.js
index 15d668fd431..fe5d11f1bd9 100644
--- a/app/assets/javascripts/static_site_editor/index.js
+++ b/app/assets/javascripts/static_site_editor/index.js
@@ -1,14 +1,14 @@
import Vue from 'vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
import StaticSiteEditor from './components/static_site_editor.vue';
import createStore from './store';
const initStaticSiteEditor = el => {
- const { projectId, path: sourcePath, returnUrl } = el.dataset;
- const isSupportedContent = 'isSupportedContent' in el.dataset;
+ const { isSupportedContent, projectId, path: sourcePath, returnUrl } = el.dataset;
const store = createStore({
initialState: {
- isSupportedContent,
+ isSupportedContent: parseBoolean(isSupportedContent),
projectId,
returnUrl,
sourcePath,
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index 37f9bdc8fa4..69253b55188 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -12,7 +12,7 @@ class Projects::RefsController < Projects::ApplicationController
before_action :authorize_download_code!
before_action only: [:logs_tree] do
- push_frontend_feature_flag(:vue_file_list_lfs_badge)
+ push_frontend_feature_flag(:vue_file_list_lfs_badge, default_enabled: true)
end
def switch
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index b8fe2a47b30..9cb345724cc 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -16,7 +16,7 @@ class Projects::TreeController < Projects::ApplicationController
before_action :authorize_edit_tree!, only: [:create_dir]
before_action only: [:show] do
- push_frontend_feature_flag(:vue_file_list_lfs_badge)
+ push_frontend_feature_flag(:vue_file_list_lfs_badge, default_enabled: true)
end
def show
diff --git a/app/models/resource_milestone_event.rb b/app/models/resource_milestone_event.rb
index a40af22061e..a0655c3a4ab 100644
--- a/app/models/resource_milestone_event.rb
+++ b/app/models/resource_milestone_event.rb
@@ -25,4 +25,8 @@ class ResourceMilestoneEvent < ResourceEvent
def self.issuable_attrs
%i(issue merge_request).freeze
end
+
+ def milestone_title
+ milestone&.title
+ end
end
diff --git a/app/services/issuable/clone/attributes_rewriter.rb b/app/services/issuable/clone/attributes_rewriter.rb
index 55f5629baac..78d3fb2e4d2 100644
--- a/app/services/issuable/clone/attributes_rewriter.rb
+++ b/app/services/issuable/clone/attributes_rewriter.rb
@@ -67,22 +67,30 @@ module Issuable
end
def copy_resource_milestone_events
- entity_key = new_entity.class.name.underscore.foreign_key
+ return unless milestone_events_supported?
copy_events(ResourceMilestoneEvent.table_name, original_entity.resource_milestone_events) do |event|
- matching_destination_milestone = matching_milestone(event.milestone.title)
-
- if matching_destination_milestone.present?
- event.attributes
- .except('id')
- .merge(entity_key => new_entity.id,
- 'milestone_id' => matching_destination_milestone.id,
- 'action' => ResourceMilestoneEvent.actions[event.action],
- 'state' => ResourceMilestoneEvent.states[event.state])
+ if event.remove?
+ event_attributes_with_milestone(event, nil)
+ else
+ matching_destination_milestone = matching_milestone(event.milestone_title)
+
+ event_attributes_with_milestone(event, matching_destination_milestone) if matching_destination_milestone.present?
end
end
end
+ def event_attributes_with_milestone(event, milestone)
+ entity_key = new_entity.class.name.underscore.foreign_key
+
+ event.attributes
+ .except('id')
+ .merge(entity_key => new_entity.id,
+ 'milestone_id' => milestone&.id,
+ 'action' => ResourceMilestoneEvent.actions[event.action],
+ 'state' => ResourceMilestoneEvent.states[event.state])
+ end
+
def copy_events(table_name, events_to_copy)
events_to_copy.find_in_batches do |batch|
events = batch.map do |event|
@@ -96,6 +104,11 @@ module Issuable
def entity_key
new_entity.class.name.parameterize('_').foreign_key
end
+
+ def milestone_events_supported?
+ original_entity.respond_to?(:resource_milestone_events) &&
+ new_entity.respond_to?(:resource_milestone_events)
+ end
end
end
end
diff --git a/changelogs/unreleased/add-ops-strategies-user-lists-table.yml b/changelogs/unreleased/add-ops-strategies-user-lists-table.yml
new file mode 100644
index 00000000000..245e4499206
--- /dev/null
+++ b/changelogs/unreleased/add-ops-strategies-user-lists-table.yml
@@ -0,0 +1,5 @@
+---
+title: Create operations_strategies_user_lists table
+merge_request: 30243
+author:
+type: added
diff --git a/changelogs/unreleased/dmishunov-clone-btn-margin.yml b/changelogs/unreleased/dmishunov-clone-btn-margin.yml
new file mode 100644
index 00000000000..197d5974ac0
--- /dev/null
+++ b/changelogs/unreleased/dmishunov-clone-btn-margin.yml
@@ -0,0 +1,5 @@
+---
+title: Added right margin to Clone Snippet button
+merge_request: 30471
+author:
+type: fixed
diff --git a/db/migrate/20200422213749_create_operations_strategies_user_lists.rb b/db/migrate/20200422213749_create_operations_strategies_user_lists.rb
new file mode 100644
index 00000000000..113f2f2f54a
--- /dev/null
+++ b/db/migrate/20200422213749_create_operations_strategies_user_lists.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class CreateOperationsStrategiesUserLists < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ create_table :operations_strategies_user_lists do |t|
+ t.references :strategy, index: false, foreign_key: { on_delete: :cascade, to_table: :operations_strategies }, null: false
+ t.references :user_list, index: true, foreign_key: { on_delete: :cascade, to_table: :operations_user_lists }, null: false
+
+ t.index [:strategy_id, :user_list_id], unique: true, name: :index_ops_strategies_user_lists_on_strategy_id_and_user_list_id
+ end
+ end
+end
diff --git a/db/structure.sql b/db/structure.sql
index 0b0f66835c1..fca564dde8c 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -4415,6 +4415,21 @@ CREATE SEQUENCE public.operations_strategies_id_seq
ALTER SEQUENCE public.operations_strategies_id_seq OWNED BY public.operations_strategies.id;
+CREATE TABLE public.operations_strategies_user_lists (
+ id bigint NOT NULL,
+ strategy_id bigint NOT NULL,
+ user_list_id bigint NOT NULL
+);
+
+CREATE SEQUENCE public.operations_strategies_user_lists_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE public.operations_strategies_user_lists_id_seq OWNED BY public.operations_strategies_user_lists.id;
+
CREATE TABLE public.operations_user_lists (
id bigint NOT NULL,
project_id bigint NOT NULL,
@@ -7489,6 +7504,8 @@ ALTER TABLE ONLY public.operations_scopes ALTER COLUMN id SET DEFAULT nextval('p
ALTER TABLE ONLY public.operations_strategies ALTER COLUMN id SET DEFAULT nextval('public.operations_strategies_id_seq'::regclass);
+ALTER TABLE ONLY public.operations_strategies_user_lists ALTER COLUMN id SET DEFAULT nextval('public.operations_strategies_user_lists_id_seq'::regclass);
+
ALTER TABLE ONLY public.operations_user_lists ALTER COLUMN id SET DEFAULT nextval('public.operations_user_lists_id_seq'::regclass);
ALTER TABLE ONLY public.packages_build_infos ALTER COLUMN id SET DEFAULT nextval('public.packages_build_infos_id_seq'::regclass);
@@ -8314,6 +8331,9 @@ ALTER TABLE ONLY public.operations_scopes
ALTER TABLE ONLY public.operations_strategies
ADD CONSTRAINT operations_strategies_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY public.operations_strategies_user_lists
+ ADD CONSTRAINT operations_strategies_user_lists_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY public.operations_user_lists
ADD CONSTRAINT operations_user_lists_pkey PRIMARY KEY (id);
@@ -9923,10 +9943,14 @@ CREATE UNIQUE INDEX index_operations_scopes_on_strategy_id_and_environment_scope
CREATE INDEX index_operations_strategies_on_feature_flag_id ON public.operations_strategies USING btree (feature_flag_id);
+CREATE INDEX index_operations_strategies_user_lists_on_user_list_id ON public.operations_strategies_user_lists USING btree (user_list_id);
+
CREATE UNIQUE INDEX index_operations_user_lists_on_project_id_and_iid ON public.operations_user_lists USING btree (project_id, iid);
CREATE UNIQUE INDEX index_operations_user_lists_on_project_id_and_name ON public.operations_user_lists USING btree (project_id, name);
+CREATE UNIQUE INDEX index_ops_strategies_user_lists_on_strategy_id_and_user_list_id ON public.operations_strategies_user_lists USING btree (strategy_id, user_list_id);
+
CREATE UNIQUE INDEX index_packages_build_infos_on_package_id ON public.packages_build_infos USING btree (package_id);
CREATE INDEX index_packages_build_infos_on_pipeline_id ON public.packages_build_infos USING btree (pipeline_id);
@@ -11584,6 +11608,9 @@ ALTER TABLE ONLY public.ci_resources
ALTER TABLE ONLY public.clusters_applications_fluentd
ADD CONSTRAINT fk_rails_4319b1dcd2 FOREIGN KEY (cluster_id) REFERENCES public.clusters(id) ON DELETE CASCADE;
+ALTER TABLE ONLY public.operations_strategies_user_lists
+ ADD CONSTRAINT fk_rails_43241e8d29 FOREIGN KEY (strategy_id) REFERENCES public.operations_strategies(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY public.lfs_file_locks
ADD CONSTRAINT fk_rails_43df7a0412 FOREIGN KEY (project_id) REFERENCES public.projects(id) ON DELETE CASCADE;
@@ -12157,6 +12184,9 @@ ALTER TABLE ONLY public.ci_daily_report_results
ALTER TABLE ONLY public.issues_self_managed_prometheus_alert_events
ADD CONSTRAINT fk_rails_cc5d88bbb0 FOREIGN KEY (issue_id) REFERENCES public.issues(id) ON DELETE CASCADE;
+ALTER TABLE ONLY public.operations_strategies_user_lists
+ ADD CONSTRAINT fk_rails_ccb7e4bc0b FOREIGN KEY (user_list_id) REFERENCES public.operations_user_lists(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY public.issue_tracker_data
ADD CONSTRAINT fk_rails_ccc0840427 FOREIGN KEY (service_id) REFERENCES public.services(id) ON DELETE CASCADE;
@@ -13486,6 +13516,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200420172927
20200420201933
20200421233150
+20200422213749
20200423075720
20200423080334
20200423080607
diff --git a/doc/administration/geo/replication/updating_the_geo_nodes.md b/doc/administration/geo/replication/updating_the_geo_nodes.md
index 3ce35798406..fa1576e19eb 100644
--- a/doc/administration/geo/replication/updating_the_geo_nodes.md
+++ b/doc/administration/geo/replication/updating_the_geo_nodes.md
@@ -11,6 +11,7 @@ Updating Geo nodes involves performing:
Depending on which version of Geo you are updating to/from, there may be
different steps.
+- [Updating to GitLab 12.9](version_specific_updates.md#updating-to-gitlab-129)
- [Updating to GitLab 12.7](version_specific_updates.md#updating-to-gitlab-127)
- [Updating to GitLab 12.2](version_specific_updates.md#updating-to-gitlab-122)
- [Updating to GitLab 12.1](version_specific_updates.md#updating-to-gitlab-121)
diff --git a/doc/administration/uploads.md b/doc/administration/uploads.md
index 294c776980d..5aff9f9c358 100644
--- a/doc/administration/uploads.md
+++ b/doc/administration/uploads.md
@@ -76,16 +76,16 @@ The connection settings match those provided by [Fog](https://github.com/fog), a
| Setting | Description | Default |
|---------|-------------|---------|
-| `provider` | Always `AWS` for compatible hosts | AWS |
+| `provider` | Always `AWS` for compatible hosts | `AWS` |
| `aws_access_key_id` | AWS credentials, or compatible | |
| `aws_secret_access_key` | AWS credentials, or compatible | |
-| `aws_signature_version` | AWS signature version to use. 2 or 4 are valid options. Digital Ocean Spaces and other providers may need 2. | 4 |
-| `enable_signature_v4_streaming` | Set to true to enable HTTP chunked transfers with [AWS v4 signatures](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html). Oracle Cloud S3 needs this to be false | true |
+| `aws_signature_version` | AWS signature version to use. `2` or `4` are valid options. Digital Ocean Spaces and other providers may need `2`. | `4` |
+| `enable_signature_v4_streaming` | Set to true to enable HTTP chunked transfers with [AWS v4 signatures](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html). Oracle Cloud S3 needs this to be `false`. | `true` |
| `region` | AWS region | us-east-1 |
-| `host` | S3 compatible host for when not using AWS, e.g. `localhost` or `storage.example.com` | s3.amazonaws.com |
+| `host` | S3 compatible host for when not using AWS, e.g. `localhost` or `storage.example.com` | `s3.amazonaws.com` |
| `endpoint` | Can be used when configuring an S3 compatible service such as [MinIO](https://min.io), by entering a URL such as `http://127.0.0.1:9000` | (optional) |
-| `path_style` | Set to true to use `host/bucket_name/object` style paths instead of `bucket_name.host/object`. Leave as false for AWS S3 | false |
-| `use_iam_profile` | Set to true to use IAM profile instead of access keys | false
+| `path_style` | Set to `true` to use `host/bucket_name/object` style paths instead of `bucket_name.host/object`. Leave as `false` for AWS S3. | `false` |
+| `use_iam_profile` | Set to `true` to use IAM profile instead of access keys | false
**In Omnibus installations:**
@@ -149,8 +149,8 @@ Note that Oracle Cloud S3 must be sure to use the following settings:
| Setting | Value |
|---------|-------|
-| `enable_signature_v4_streaming` | false |
-| `path_style` | true |
+| `enable_signature_v4_streaming` | `false` |
+| `path_style` | `true` |
If `enable_signature_v4_streaming` is set to `true`, you may see the
following error:
@@ -165,7 +165,7 @@ The connection settings match those provided by [Fog](https://github.com/fog), a
| Setting | Description | Default |
|---------|-------------|---------|
-| `provider` | Always `OpenStack` for compatible hosts | OpenStack |
+| `provider` | Always `OpenStack` for compatible hosts | `OpenStack` |
| `openstack_username` | OpenStack username | |
| `openstack_api_key` | OpenStack API key | |
| `openstack_temp_url_key` | OpenStack key for generating temporary urls | |
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 14f81d7d327..02cfe38fae2 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -630,7 +630,7 @@ the `epic` property:
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042). This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
-**Note**: The `epic_iid` attribute is deprecated and [will be removed in 13.0](https://gitlab.com/gitlab-org/gitlab/issues/35157).
+**Note**: The `epic_iid` attribute is deprecated and [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/issues/35157).
Please use `iid` of the `epic` attribute instead.
## New issue
@@ -657,7 +657,7 @@ POST /projects/:id/issues
| `discussion_to_resolve` | string | no | The ID of a discussion to resolve. This will fill in the issue with a default description and mark the discussion as resolved. Use in combination with `merge_request_to_resolve_discussions_of`. |
| `weight` **(STARTER)** | integer | no | The weight of the issue. Valid values are greater than or equal to 0. |
| `epic_id` **(ULTIMATE)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
-| `epic_iid` **(ULTIMATE)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in 13.0](https://gitlab.com/gitlab-org/gitlab/issues/35157)) |
+| `epic_iid` **(ULTIMATE)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/issues/35157)) |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/issues?title=Issues%20with%20auth&labels=bug
@@ -773,7 +773,7 @@ PUT /projects/:id/issues/:issue_iid
| `weight` **(STARTER)** | integer | no | The weight of the issue. Valid values are greater than or equal to 0. 0 |
| `discussion_locked` | boolean | no | Flag indicating if the issue's discussion is locked. If the discussion is locked only project members can add or edit comments. |
| `epic_id` **(ULTIMATE)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
-| `epic_iid` **(ULTIMATE)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in 13.0](https://gitlab.com/gitlab-org/gitlab/issues/35157)) |
+| `epic_iid` **(ULTIMATE)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/issues/35157)) |
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/issues/85?state_event=close
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 3652b31c1aa..27616f6c1ff 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -142,21 +142,31 @@ Starting with GitLab 12.0, Git is required to be compiled with `libpcre2`.
Find out if that's the case:
```shell
-ldd /usr/local/bin/git | grep pcre2
+ldd $(which git) | grep pcre2
```
-The output should be similar to:
+The output should contain `libpcre2-8.so.0`.
-```plaintext
-libpcre2-8.so.0 => /usr/lib/libpcre2-8.so.0 (0x00007f08461c3000)
+Is the system packaged Git too old, or not compiled with pcre2?
+Remove it:
+
+```shell
+sudo apt-get remove git-core
```
-Is the system packaged Git too old, or not compiled with pcre2? Remove it and compile from source:
+On Ubuntu, install Git from [its official PPA](https://git-scm.com/download/linux):
```shell
-# Remove packaged Git
-sudo apt-get remove git-core
+# run as root!
+add-apt-repository ppa:git-core/ppa
+apt update
+apt install git
+# repeat libpcre2 check as above
+```
+On Debian, use the following compilation instructions:
+
+```shell
# Install dependencies
sudo apt-get install -y libcurl4-openssl-dev libexpat1-dev gettext libz-dev libssl-dev build-essential
@@ -180,7 +190,7 @@ make prefix=/usr/local all
# Install into /usr/local/bin
sudo make prefix=/usr/local install
-# When editing config/gitlab.yml (Step 5), change the git -> bin_path to /usr/local/bin/git
+# When editing config/gitlab.yml later, change the git -> bin_path to /usr/local/bin/git
```
For the [Custom Favicon](../user/admin_area/appearance.md#favicon) to work, GraphicsMagick
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index 5634ad95cf7..2afdeccb764 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -51,7 +51,7 @@ that are in common for all providers that we need to consider.
automatically create an account. It defaults to `false`. If `false` users must
be created manually or they will not be able to sign in via OmniAuth.
- `auto_link_ldap_user` can be used if you have [LDAP / ActiveDirectory](ldap.md)
- integration enabled. It defaults to false. When enabled, users automatically
+ integration enabled. It defaults to `false`. When enabled, users automatically
created through an OmniAuth provider will have their LDAP identity created in GitLab as well.
- `block_auto_created_users` defaults to `true`. If `true` auto created users will
be blocked by default and will have to be unblocked by an administrator before
diff --git a/doc/user/packages/index.md b/doc/user/packages/index.md
index 8e98dd70346..cb3cb26ebb1 100644
--- a/doc/user/packages/index.md
+++ b/doc/user/packages/index.md
@@ -112,7 +112,6 @@ are adding support for [PHP](https://gitlab.com/gitlab-org/gitlab/-/merge_reques
| [Opkg](https://gitlab.com/gitlab-org/gitlab/issues/36894) | Optimize your work with OpenWrt using Opkg repositories. |
| [P2](https://gitlab.com/gitlab-org/gitlab/issues/36895) | Host all your Eclipse plugins in your own GitLab P2 repository. |
| [Puppet](https://gitlab.com/gitlab-org/gitlab/issues/36897) | Configuration management meets repository management with Puppet repositories. |
-| [PyPi](https://gitlab.com/gitlab-org/gitlab/issues/10483) | Host PyPi distributions. |
| [RPM](https://gitlab.com/gitlab-org/gitlab/issues/5932) | Distribute RPMs directly from GitLab. |
| [RubyGems](https://gitlab.com/gitlab-org/gitlab/issues/803) | Use GitLab to host your own gems. |
| [SBT](https://gitlab.com/gitlab-org/gitlab/issues/36898) | Resolve dependencies from and deploy build output to SBT repositories when running SBT builds. |
diff --git a/doc/user/packages/npm_registry/index.md b/doc/user/packages/npm_registry/index.md
index e66b3d1ac63..5187201ec60 100644
--- a/doc/user/packages/npm_registry/index.md
+++ b/doc/user/packages/npm_registry/index.md
@@ -363,6 +363,14 @@ You do not need a token to run `npm install` unless your project is private (the
NPM_TOKEN=<your_token> npm install
```
+### `npm install` returns `npm ERR! 403 Forbidden`
+
+- Check that your token is not expired and has appropriate permissions.
+- Check if you have attempted to publish a package with a name that already exists within a given scope.
+- Ensure the scoped packages URL includes a trailing slash:
+ - Correct: `//gitlab.com/api/v4/packages/npm/`
+ - Incorrect: `//gitlab.com/api/v4/packages/npm`
+
## NPM dependencies metadata
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/11867) in GitLab Premium 12.6.
diff --git a/doc/user/project/file_lock.md b/doc/user/project/file_lock.md
index b5350515c30..9069a231db4 100644
--- a/doc/user/project/file_lock.md
+++ b/doc/user/project/file_lock.md
@@ -4,7 +4,8 @@
Working with multiple people on the same file can be a risk. Conflicts when merging a non-text file are hard to overcome and will require a lot of manual work to resolve. File Locking helps you avoid these merge conflicts and better manage your binary files.
-With File Locaking, you can lock any file or directory, make your changes, and then unlock it so another member of the team can edit it.
+With File Locking, you can lock any file or directory, make your changes, and
+then unlock it so another member of the team can edit it.
## Overview
diff --git a/doc/user/project/issues/due_dates.md b/doc/user/project/issues/due_dates.md
index f70597f6875..0be0cdd11bd 100644
--- a/doc/user/project/issues/due_dates.md
+++ b/doc/user/project/issues/due_dates.md
@@ -24,6 +24,11 @@ Changes are saved immediately.
![Edit a due date via the sidebar](img/due_dates_edit_sidebar.png)
+The last way to set a due date is by using [quick actions](../quick_actions.md), directly in an issue's description or comment:
+
+- `/due <date>`: set due date. Examples of valid `<date>` include `in 2 days`, `this Friday`, and `December 31st`.
+- `/remove_due_date`: remove due date.
+
## Making use of due dates
Issues that have a due date can be easily seen in the issue tracker,
diff --git a/lib/gitlab/static_site_editor/config.rb b/lib/gitlab/static_site_editor/config.rb
index 41d54ee0a92..1862d949817 100644
--- a/lib/gitlab/static_site_editor/config.rb
+++ b/lib/gitlab/static_site_editor/config.rb
@@ -22,7 +22,7 @@ module Gitlab
project: project.path,
namespace: project.namespace.path,
return_url: return_url,
- is_supported_content: supported_content?
+ is_supported_content: supported_content?.to_s
}
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index b12731340e5..87736edd036 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2994,9 +2994,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "Batch operations"
-msgstr ""
-
msgid "BatchComments|Delete all pending comments"
msgstr ""
@@ -9215,7 +9212,10 @@ msgstr ""
msgid "Filter by milestone name"
msgstr ""
-msgid "Filter by name..."
+msgid "Filter by name"
+msgstr ""
+
+msgid "Filter by status"
msgstr ""
msgid "Filter by two-factor authentication"
@@ -11208,6 +11208,9 @@ msgstr ""
msgid "In order to tailor your experience with GitLab we<br>would like to know a bit more about you."
msgstr ""
+msgid "In progress"
+msgstr ""
+
msgid "In the next step, you'll be able to select the projects you want to import."
msgstr ""
@@ -17592,6 +17595,9 @@ msgstr ""
msgid "Resync"
msgstr ""
+msgid "Resync all"
+msgstr ""
+
msgid "Resync all %{replicableType}"
msgstr ""
diff --git a/package.json b/package.json
index ec77c17a82d..5b630d0c5f4 100644
--- a/package.json
+++ b/package.json
@@ -40,7 +40,7 @@
"@babel/preset-env": "^7.8.4",
"@gitlab/at.js": "1.5.5",
"@gitlab/svgs": "1.121.0",
- "@gitlab/ui": "12.3.0",
+ "@gitlab/ui": "13.5.0",
"@gitlab/visual-review-tools": "1.6.1",
"@sentry/browser": "^5.10.2",
"@sourcegraph/code-host-integration": "0.0.37",
diff --git a/spec/frontend/autosave_spec.js b/spec/frontend/autosave_spec.js
index 3119477f385..bbdf3c6f91d 100644
--- a/spec/frontend/autosave_spec.js
+++ b/spec/frontend/autosave_spec.js
@@ -10,6 +10,8 @@ describe('Autosave', () => {
const field = $('<textarea></textarea>');
const key = 'key';
const fallbackKey = 'fallbackKey';
+ const lockVersionKey = 'lockVersionKey';
+ const lockVersion = 1;
describe('class constructor', () => {
beforeEach(() => {
@@ -30,6 +32,13 @@ describe('Autosave', () => {
expect(AccessorUtilities.isLocalStorageAccessSafe).toHaveBeenCalled();
expect(autosave.isLocalStorageAvailable).toBe(true);
});
+
+ it('should set .isLocalStorageAvailable if lockVersion is passed', () => {
+ autosave = new Autosave(field, key, null, lockVersion);
+
+ expect(AccessorUtilities.isLocalStorageAccessSafe).toHaveBeenCalled();
+ expect(autosave.isLocalStorageAvailable).toBe(true);
+ });
});
describe('restore', () => {
@@ -96,6 +105,40 @@ describe('Autosave', () => {
});
});
+ describe('getSavedLockVersion', () => {
+ beforeEach(() => {
+ autosave = {
+ field,
+ key,
+ lockVersionKey,
+ };
+ });
+
+ describe('if .isLocalStorageAvailable is `false`', () => {
+ beforeEach(() => {
+ autosave.isLocalStorageAvailable = false;
+
+ Autosave.prototype.getSavedLockVersion.call(autosave);
+ });
+
+ it('should not call .getItem', () => {
+ expect(window.localStorage.getItem).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('if .isLocalStorageAvailable is `true`', () => {
+ beforeEach(() => {
+ autosave.isLocalStorageAvailable = true;
+ });
+
+ it('should call .getItem', () => {
+ Autosave.prototype.getSavedLockVersion.call(autosave);
+
+ expect(window.localStorage.getItem).toHaveBeenCalledWith(lockVersionKey);
+ });
+ });
+ });
+
describe('save', () => {
beforeEach(() => {
autosave = { reset: jest.fn() };
@@ -128,10 +171,51 @@ describe('Autosave', () => {
});
});
+ describe('save with lockVersion', () => {
+ beforeEach(() => {
+ autosave = {
+ field,
+ key,
+ lockVersionKey,
+ lockVersion,
+ isLocalStorageAvailable: true,
+ };
+ });
+
+ describe('lockVersion is valid', () => {
+ it('should call .setItem', () => {
+ Autosave.prototype.save.call(autosave);
+ expect(window.localStorage.setItem).toHaveBeenCalledWith(lockVersionKey, lockVersion);
+ });
+
+ it('should call .setItem when version is 0', () => {
+ autosave.lockVersion = 0;
+ Autosave.prototype.save.call(autosave);
+ expect(window.localStorage.setItem).toHaveBeenCalledWith(
+ lockVersionKey,
+ autosave.lockVersion,
+ );
+ });
+ });
+
+ describe('lockVersion is invalid', () => {
+ it('should not call .setItem with lockVersion', () => {
+ delete autosave.lockVersion;
+ Autosave.prototype.save.call(autosave);
+
+ expect(window.localStorage.setItem).not.toHaveBeenCalledWith(
+ lockVersionKey,
+ autosave.lockVersion,
+ );
+ });
+ });
+ });
+
describe('reset', () => {
beforeEach(() => {
autosave = {
key,
+ lockVersionKey,
};
});
@@ -156,6 +240,7 @@ describe('Autosave', () => {
it('should call .removeItem', () => {
expect(window.localStorage.removeItem).toHaveBeenCalledWith(key);
+ expect(window.localStorage.removeItem).toHaveBeenCalledWith(lockVersionKey);
});
});
});
@@ -166,8 +251,8 @@ describe('Autosave', () => {
field,
key,
fallbackKey,
+ isLocalStorageAvailable: true,
};
- autosave.isLocalStorageAvailable = true;
});
it('should call .getItem', () => {
@@ -185,7 +270,8 @@ describe('Autosave', () => {
it('should call .removeItem for key and fallbackKey', () => {
Autosave.prototype.reset.call(autosave);
- expect(window.localStorage.removeItem).toHaveBeenCalledTimes(2);
+ expect(window.localStorage.removeItem).toHaveBeenCalledWith(fallbackKey);
+ expect(window.localStorage.removeItem).toHaveBeenCalledWith(key);
});
});
});
diff --git a/spec/lib/gitlab/static_site_editor/config_spec.rb b/spec/lib/gitlab/static_site_editor/config_spec.rb
index 8f61476722d..b32af912ad9 100644
--- a/spec/lib/gitlab/static_site_editor/config_spec.rb
+++ b/spec/lib/gitlab/static_site_editor/config_spec.rb
@@ -24,38 +24,38 @@ describe Gitlab::StaticSiteEditor::Config do
project: 'project',
project_id: project.id,
return_url: 'http://example.com',
- is_supported_content: true
+ is_supported_content: 'true'
)
end
context 'when branch is not master' do
let(:ref) { 'my-branch' }
- it { is_expected.to include(is_supported_content: false) }
+ it { is_expected.to include(is_supported_content: 'false') }
end
context 'when file does not have a markdown extension' do
let(:file_path) { 'README.txt' }
- it { is_expected.to include(is_supported_content: false) }
+ it { is_expected.to include(is_supported_content: 'false') }
end
context 'when file does not have an extension' do
let(:file_path) { 'README' }
- it { is_expected.to include(is_supported_content: false) }
+ it { is_expected.to include(is_supported_content: 'false') }
end
context 'when file does not exist' do
let(:file_path) { 'UNKNOWN.md' }
- it { is_expected.to include(is_supported_content: false) }
+ it { is_expected.to include(is_supported_content: 'false') }
end
context 'when repository is empty' do
let(:project) { create(:project_empty_repo) }
- it { is_expected.to include(is_supported_content: false) }
+ it { is_expected.to include(is_supported_content: 'false') }
end
end
end
diff --git a/spec/models/resource_milestone_event_spec.rb b/spec/models/resource_milestone_event_spec.rb
index bf8672f95c9..3f8d8b4c1df 100644
--- a/spec/models/resource_milestone_event_spec.rb
+++ b/spec/models/resource_milestone_event_spec.rb
@@ -78,4 +78,21 @@ describe ResourceMilestoneEvent, type: :model do
let(:query_method) { :remove? }
end
end
+
+ describe '#milestone_title' do
+ let(:milestone) { create(:milestone, title: 'v2.3') }
+ let(:event) { create(:resource_milestone_event, milestone: milestone) }
+
+ it 'returns the expected title' do
+ expect(event.milestone_title).to eq('v2.3')
+ end
+
+ context 'when milestone is nil' do
+ let(:event) { create(:resource_milestone_event, milestone: nil) }
+
+ it 'returns nil' do
+ expect(event.milestone_title).to be_nil
+ end
+ end
+ end
end
diff --git a/spec/requests/api/terraform/state_spec.rb b/spec/requests/api/terraform/state_spec.rb
index 88c277f4e08..844cd948411 100644
--- a/spec/requests/api/terraform/state_spec.rb
+++ b/spec/requests/api/terraform/state_spec.rb
@@ -78,6 +78,14 @@ describe API::Terraform::State do
expect(response).to have_gitlab_http_status(:ok)
end
+
+ context 'on Unicorn', :unicorn do
+ it 'updates the state' do
+ expect { request }.to change { Terraform::State.count }.by(0)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
end
context 'without body' do
@@ -112,6 +120,14 @@ describe API::Terraform::State do
expect(response).to have_gitlab_http_status(:ok)
end
+
+ context 'on Unicorn', :unicorn do
+ it 'creates a new state' do
+ expect { request }.to change { Terraform::State.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
end
context 'without body' do
diff --git a/spec/services/issuable/clone/attributes_rewriter_spec.rb b/spec/services/issuable/clone/attributes_rewriter_spec.rb
index 9111b19d7b7..8cb37917239 100644
--- a/spec/services/issuable/clone/attributes_rewriter_spec.rb
+++ b/spec/services/issuable/clone/attributes_rewriter_spec.rb
@@ -89,7 +89,7 @@ describe Issuable::Clone::AttributesRewriter do
create_event(milestone1_project1)
create_event(milestone2_project1)
- create_event(milestone1_project1, 'remove')
+ create_event(nil, 'remove')
create_event(milestone3_project1)
end
@@ -101,7 +101,7 @@ describe Issuable::Clone::AttributesRewriter do
expect_milestone_event(new_issue_milestone_events.first, milestone: milestone1_project2, action: 'add', state: 'opened')
expect_milestone_event(new_issue_milestone_events.second, milestone: milestone2_project2, action: 'add', state: 'opened')
- expect_milestone_event(new_issue_milestone_events.third, milestone: milestone1_project2, action: 'remove', state: 'opened')
+ expect_milestone_event(new_issue_milestone_events.third, milestone: nil, action: 'remove', state: 'opened')
end
def create_event(milestone, action = 'add')
@@ -109,7 +109,7 @@ describe Issuable::Clone::AttributesRewriter do
end
def expect_milestone_event(event, expected_attrs)
- expect(event.milestone_id).to eq(expected_attrs[:milestone].id)
+ expect(event.milestone_id).to eq(expected_attrs[:milestone]&.id)
expect(event.action).to eq(expected_attrs[:action])
expect(event.state).to eq(expected_attrs[:state])
end
diff --git a/spec/support/unicorn.rb b/spec/support/unicorn.rb
new file mode 100644
index 00000000000..0b01fc9e26c
--- /dev/null
+++ b/spec/support/unicorn.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+REQUEST_CLASSES = [
+ ::Grape::Request,
+ ::Rack::Request
+].freeze
+
+def request_body_class
+ return ::Unicorn::TeeInput if defined?(::Unicorn)
+
+ Class.new(StringIO) do
+ def string
+ raise NotImplementedError, '#string is only valid under Puma which uses StringIO, use #read instead'
+ end
+ end
+end
+
+RSpec.configure do |config|
+ config.before(:each, :unicorn) do
+ REQUEST_CLASSES.each do |request_class|
+ allow_any_instance_of(request_class)
+ .to receive(:body).and_wrap_original do |m, *args|
+ request_body_class.new(m.call(*args).read)
+ end
+ end
+ end
+end
diff --git a/yarn.lock b/yarn.lock
index a0298450219..5c2e6274a32 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -786,10 +786,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.121.0.tgz#77083a68f72e9aa0e294da7715f378eef13b839e"
integrity sha512-scz/6Y/eED7RMFLAlhT6PwXwe0Wj8ivnRsyulk9NXKoqUmAqZliNmBmzYsHy5bFf9NB6xVV/rOk1/92nbi/Yaw==
-"@gitlab/ui@12.3.0":
- version "12.3.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-12.3.0.tgz#9234205887675a6d13a51945ee62efc3c8b5e890"
- integrity sha512-XrHC2pK7qlwy6K3OR/+iCP8TDewn3jaDIHCfHjt/KOwvD5LsEmam9RHjTiZ4epPZXLv4+JxCzbc4R+euEbIQ7g==
+"@gitlab/ui@13.5.0":
+ version "13.5.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-13.5.0.tgz#bb8d90baea80066e5360457386d8153724998043"
+ integrity sha512-f4k6zKcJWRNV5ho7SXz0gL4VU4n+ljB52VrUrfJ1WTrESGpIFlTU17/Ac4ZMYySZuUXzmLulf9BXEN5HWCetTQ==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"