Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
45999bfdec
commit
c2908ec6a0
30 changed files with 320 additions and 60 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
/>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -25,4 +25,8 @@ class ResourceMilestoneEvent < ResourceEvent
|
|||
def self.issuable_attrs
|
||||
%i(issue merge_request).freeze
|
||||
end
|
||||
|
||||
def milestone_title
|
||||
milestone&.title
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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 event.remove?
|
||||
event_attributes_with_milestone(event, nil)
|
||||
else
|
||||
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])
|
||||
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
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Create operations_strategies_user_lists table
|
||||
merge_request: 30243
|
||||
author:
|
||||
type: added
|
5
changelogs/unreleased/dmishunov-clone-btn-margin.yml
Normal file
5
changelogs/unreleased/dmishunov-clone-btn-margin.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Added right margin to Clone Snippet button
|
||||
merge_request: 30471
|
||||
author:
|
||||
type: fixed
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 | |
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 and compile from source:
|
||||
Is the system packaged Git too old, or not compiled with pcre2?
|
||||
Remove it:
|
||||
|
||||
```shell
|
||||
# Remove packaged Git
|
||||
sudo apt-get remove git-core
|
||||
```
|
||||
|
||||
On Ubuntu, install Git from [its official PPA](https://git-scm.com/download/linux):
|
||||
|
||||
```shell
|
||||
# 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. |
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 ""
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
27
spec/support/unicorn.rb
Normal file
27
spec/support/unicorn.rb
Normal file
|
@ -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
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue