Commit 24256212 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent d933bc5a
......@@ -16,9 +16,6 @@ export default {
]),
...mapState({ items: 'machineTypes' }),
...mapGetters(['hasZone', 'hasMachineType']),
allDropdownsSelected() {
return this.projectHasBillingEnabled && this.hasZone && this.hasMachineType;
},
isDisabled() {
return (
this.isLoading ||
......@@ -65,22 +62,10 @@ export default {
.catch(this.fetchFailureHandler);
}
},
selectedMachineType() {
this.enableSubmit();
},
},
methods: {
...mapActions(['fetchMachineTypes']),
...mapActions({ setItem: 'setMachineType' }),
enableSubmit() {
if (this.allDropdownsSelected) {
const submitButtonEl = document.querySelector('.js-gke-cluster-creation-submit');
if (submitButtonEl) {
submitButtonEl.removeAttribute('disabled');
}
}
},
},
};
</script>
......
<script>
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters(['hasValidData']),
},
};
</script>
<template>
<button
type="submit"
:disabled="!hasValidData"
class="js-gke-cluster-creation-submit btn btn-success"
>
{{ s__('ClusterIntegration|Create Kubernetes cluster') }}
</button>
</template>
......@@ -4,6 +4,10 @@ import Flash from '~/flash';
import GkeProjectIdDropdown from './components/gke_project_id_dropdown.vue';
import GkeZoneDropdown from './components/gke_zone_dropdown.vue';
import GkeMachineTypeDropdown from './components/gke_machine_type_dropdown.vue';
import GkeSubmitButton from './components/gke_submit_button.vue';
import store from './store';
import * as CONSTANTS from './constants';
const mountComponent = (entryPoint, component, componentName, extraProps = {}) => {
......@@ -14,6 +18,7 @@ const mountComponent = (entryPoint, component, componentName, extraProps = {}) =
return new Vue({
el,
store,
components: {
[componentName]: component,
},
......@@ -50,6 +55,10 @@ const mountGkeMachineTypeDropdown = () => {
);
};
const mountGkeSubmitButton = () => {
mountComponent('.js-gke-cluster-creation-submit-container', GkeSubmitButton, 'gke-submit-button');
};
const gkeDropdownErrorHandler = () => {
Flash(CONSTANTS.GCP_API_ERROR);
};
......@@ -72,6 +81,7 @@ const initializeGapiClient = () => {
mountGkeProjectIdDropdown();
mountGkeZoneDropdown();
mountGkeMachineTypeDropdown();
mountGkeSubmitButton();
})
.catch(gkeDropdownErrorHandler);
};
......
export const hasProject = state => Boolean(state.selectedProject.projectId);
export const hasZone = state => Boolean(state.selectedZone);
export const hasMachineType = state => Boolean(state.selectedMachineType);
export const hasValidData = (state, getters) =>
Boolean(state.projectHasBillingEnabled) && getters.hasZone && getters.hasMachineType;
......@@ -4,6 +4,7 @@ import { mapActions, mapState, mapGetters } from 'vuex';
import store from 'ee_else_ce/mr_notes/stores';
import notesApp from '../notes/components/notes_app.vue';
import discussionKeyboardNavigator from '../notes/components/discussion_keyboard_navigator.vue';
import initWidget from '../vue_merge_request_widget';
export default () => {
// eslint-disable-next-line no-new
......@@ -32,11 +33,22 @@ export default () => {
...mapState({
activeTab: state => state.page.activeTab,
}),
isShowTabActive() {
return this.activeTab === 'show';
},
},
watch: {
discussionTabCounter() {
this.updateDiscussionTabCounter();
},
isShowTabActive: {
handler(newVal) {
if (newVal) {
initWidget();
}
},
immediate: true,
},
},
created() {
this.setActiveTab(window.mrTabs.getCurrentAction());
......@@ -69,7 +81,7 @@ export default () => {
noteableData: this.noteableData,
notesData: this.notesData,
userData: this.currentUserData,
shouldShow: this.activeTab === 'show',
shouldShow: this.isShowTabActive,
helpPagePath: this.helpPagePath,
},
}),
......
......@@ -7,7 +7,6 @@ import initPipelines from '~/commit/pipelines/pipelines_bundle';
import initVueIssuableSidebarApp from '~/issuable_sidebar/sidebar_bundle';
import initSourcegraph from '~/sourcegraph';
import initPopover from '~/mr_tabs_popover';
import initWidget from '../../../vue_merge_request_widget';
export default function() {
new ZenMode(); // eslint-disable-line no-new
......@@ -20,7 +19,6 @@ export default function() {
new ShortcutsIssuable(true); // eslint-disable-line no-new
handleLocationHash();
howToMerge();
initWidget();
initSourcegraph();
const tabHighlightEl = document.querySelector('.js-tabs-feature-highlight');
......
......@@ -5,6 +5,8 @@ import Translate from '../vue_shared/translate';
Vue.use(Translate);
export default () => {
if (gl.mrWidget) return;
gl.mrWidgetData.gitlabLogo = gon.gitlab_logo;
const vm = new Vue(MrWidgetOptions);
......
......@@ -135,15 +135,11 @@ export default {
},
},
mounted() {
if (gon && gon.features && gon.features.asyncMrWidget) {
MRWidgetService.fetchInitialData()
.then(({ data }) => this.initWidget(data))
.catch(() =>
createFlash(__('Unable to load the merge request widget. Try reloading the page.')),
);
} else {
this.initWidget();
}
MRWidgetService.fetchInitialData()
.then(({ data }) => this.initWidget(data))
.catch(() =>
createFlash(__('Unable to load the merge request widget. Try reloading the page.')),
);
},
beforeDestroy() {
eventHub.$off('mr.discussion.updated', this.checkStatus);
......
......@@ -25,7 +25,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
before_action do
push_frontend_feature_flag(:vue_issuable_sidebar, @project.group)
push_frontend_feature_flag(:async_mr_widget, @project)
end
around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :discussions]
......
......@@ -67,14 +67,6 @@ class MergeRequestWidgetEntity < Grape::Entity
end
end
def as_json(options = {})
return super(options) if Feature.enabled?(:async_mr_widget)
super(options)
.merge(MergeRequestPollCachedWidgetEntity.new(object, **@options.opts_hash).as_json(options))
.merge(MergeRequestPollWidgetEntity.new(object, **@options.opts_hash).as_json(options))
end
private
delegate :current_user, to: :request
......
......@@ -11,6 +11,12 @@ module Groups
end
def execute
unless @current_user.can?(:admin_group, @group)
raise ::Gitlab::ImportExport::Error.new(
"User with ID: %s does not have permission to Group %s with ID: %s." %
[@current_user.id, @group.name, @group.id])
end
save!
end
......
......@@ -79,6 +79,6 @@
= s_('ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster.')
= link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'gitlab-managed-clusters'), target: '_blank'
.form-group
.form-group.js-gke-cluster-creation-submit-container
= field.submit s_('ClusterIntegration|Create Kubernetes cluster'),
class: 'js-gke-cluster-creation-submit btn btn-success', disabled: true
---
title: Remove invalid data from jira_tracker_data table
merge_request: 23621
author:
type: fixed
---
title: Groups::ImportExport::ExportService to require admin_group permission
merge_request: 23434
author:
type: changed
---
title: Fetch merge request widget data asynchronous
merge_request: 23594
author:
type: changed
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RemoveInvalidJiraData < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
sql = "DELETE FROM jira_tracker_data WHERE \
(length(encrypted_api_url) > 0 AND encrypted_api_url_iv IS NULL) \
OR (length(encrypted_url) > 0 AND encrypted_url_iv IS NULL) \
OR (length(encrypted_username) > 0 AND encrypted_username_iv IS NULL) \
OR (length(encrypted_password) > 0 AND encrypted_password_iv IS NULL)"
execute(sql)
end
def down
# We need to figure out why migrating data to jira_tracker_data table
# failed and then can recreate the data
end
end
......@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_01_21_132641) do
ActiveRecord::Schema.define(version: 2020_01_23_155929) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
......
......@@ -144,7 +144,7 @@ otherwise you will run into conflicts.
1. Validate using:
```sh
```shell
openssl s_client -showcerts -servername gitlab.example.com -connect gitlab.example.com:443 > cacert.pem
```
......@@ -156,7 +156,7 @@ If your certificate provider provides the CA Bundle certificates, append them to
1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
configure it with the following settings:
```
```yaml
registry:
enabled: true
host: gitlab.example.com
......@@ -408,7 +408,7 @@ when you [deployed your docker registry](https://docs.docker.com/registry/deploy
`s3` storage driver example:
```yml
```yaml
storage:
s3:
accesskey: 's3-access-key'
......@@ -616,7 +616,7 @@ Before diving in to the following sections, here's some basic troubleshooting:
If you're using a self-signed certificate with your Container Registry, you
might encounter issues during the CI jobs like the following:
```
```plaintext
Error response from daemon: Get registry.example.com/v1/users/: x509: certificate signed by unknown authority
```
......@@ -666,7 +666,7 @@ Container Registry > Authorization token duration (minutes)**.
When using AWS S3 with the GitLab registry, an error may occur when pushing
large images. Look in the Registry log for the following error:
```
```plaintext
level=error msg="response completed with error" err.code=unknown err.detail="unexpected EOF" err.message="unknown error"
```
......@@ -813,7 +813,7 @@ diagnose a problem with the S3 setup.
A user attempted to enable an S3-backed Registry. The `docker login` step went
fine. However, when pushing an image, the output showed:
```text
```plaintext
The push refers to a repository [s3-testing.myregistry.com:4567/root/docker-test/docker-image]
dc5e59c14160: Pushing [==================================================>] 14.85 kB
03c20c1a019a: Pushing [==================================================>] 2.048 kB
......@@ -859,27 +859,27 @@ The following installation instructions assume you are running Ubuntu:
Enter <kbd>CTRL</kbd>-<kbd>C</kbd> to quit.
1. Install the certificate from `~/.mitmproxy` to your system:
```sh
```shell
sudo cp ~/.mitmproxy/mitmproxy-ca-cert.pem /usr/local/share/ca-certificates/mitmproxy-ca-cert.crt
sudo update-ca-certificates
```
If successful, the output should indicate that a certificate was added:
```sh
```shell
Updating certificates in /etc/ssl/certs... 1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....done.
```
To verify that the certificates are properly installed, run:
```sh
```shell
mitmproxy --port 9000
```
This will run mitmproxy on port `9000`. In another window, run:
```sh
```shell
curl --proxy http://localhost:9000 https://httpbin.org/status/200
```
......@@ -892,7 +892,7 @@ For Docker to connect through a proxy, you must start the Docker daemon with the
proper environment variables. The easiest way is to shutdown Docker (e.g. `sudo initctl stop docker`)
and then run Docker by hand. As root, run:
```sh
```shell
export HTTP_PROXY="http://localhost:9000"
export HTTPS_PROXY="https://localhost:9000"
docker daemon --debug
......@@ -905,7 +905,7 @@ This will launch the Docker daemon and proxy all connections through mitmproxy.
Now that we have mitmproxy and Docker running, we can attempt to login and push
a container image. You may need to run as root to do this. For example:
```sh
```shell
docker login s3-testing.myregistry.com:4567
docker push s3-testing.myregistry.com:4567/root/docker-test/docker-image
```
......
......@@ -54,6 +54,7 @@ description: 'Learn how to contribute to GitLab.'
- [How to dump production data to staging](db_dump.md)
- [Working with the GitHub importer](github_importer.md)
- [Import/Export development documentation](import_export.md)
- [Test Import Project](import_project.md)
- [Elasticsearch integration docs](elasticsearch.md)
- [Working with Merge Request diffs](diffs.md)
- [Kubernetes integration guidelines](kubernetes.md)
......
# Test Import Project
For testing, we can import our own [GitLab CE](https://gitlab.com/gitlab-org/gitlab-foss/) project (named `gitlabhq` in this case) under a group named `qa-perf-testing`. Project tarballs that can be used for testing can be found over on the [performance-data](https://gitlab.com/gitlab-org/quality/performance-data) project. A different project could be used if required.
There are several options for importing the project into your GitLab environment. They are detailed as follows with the assumption that the recommended group `qa-perf-testing` and project `gitlabhq` are being set up.
## Importing the project
There are several ways to import a project.
### Importing via UI
The first option is to simply [import the Project tarball file via the GitLab UI](../user/project/settings/import_export.md#importing-the-project):
1. Create the group `qa-perf-testing`
1. Import the [GitLab FOSS project tarball](https://gitlab.com/gitlab-org/quality/performance-data/raw/master/gitlabhq_export.tar.gz) into the Group.
It should take up to 15 minutes for the project to fully import. You can head to the project's main page for the current status.
NOTE: **Note:** This method ignores all the errors silently (including the ones related to `GITALY_DISABLE_REQUEST_LIMITS`) and is used by GitLab's users. For development and testing, check the other methods below.
### Importing via the `import-project` script
A convenient script, [`bin/import-project`](https://gitlab.com/gitlab-org/quality/performance/blob/master/bin/import-project), is provided with [performance](https://gitlab.com/gitlab-org/quality/performance) project to import the Project tarball into a GitLab environment via API from the terminal.
Note that to use the script, it will require some preparation if you haven't done so already:
1. First, set up [`Ruby`](https://www.ruby-lang.org/en/documentation/installation/) and [`Ruby Bundler`](https://bundler.io) if they aren't already available on the machine.
1. Next, install the required Ruby Gems via Bundler with `bundle install`.
For details how to use `bin/import-project`, run:
```sh
bin/import-project --help
```
The process should take up to 15 minutes for the project to import fully. The script will keep checking periodically for the status and exit once import has completed.
### Importing via GitHub
There is also an option to [import the project via GitHub](../user/project/import/github.md):
1. Create the group `qa-perf-testing`
1. Import the GitLab FOSS repository that's [mirrored on GitHub](https://github.com/gitlabhq/gitlabhq) into the group via the UI.
This method will take longer to import than the other methods and will depend on several factors. It's recommended to use the other methods.
### Importing via a rake task
[`import.rake`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/tasks/gitlab/import_export/import.rake) was introduced for importing large GitLab project exports.
As part of this script we also disable direct and background upload to avoid situations where a huge archive is being uploaded to GCS (while being inside a transaction, which can cause idle transaction timeouts).
We can simply run this script from the terminal:
```sh
bundle exec rake "gitlab:import_export:import[root, root, testingprojectimport, /path/to/file.tar.gz]"
```
### Importing via the Rails console
The last option is to import a project using a Rails console:
1. Start a Ruby on Rails console:
```sh
# Omnibus GitLab
gitlab-rails console
# For installations from source
sudo -u git -H bundle exec rails console RAILS_ENV=production
```
1. Create a project and run `ProjectTreeRestorer`:
```ruby
shared_class = Struct.new(:export_path) do
def error(message)
raise message
end
end
user = User.first
shared = shared_class.new(path)
project = Projects::CreateService.new(user, { name: name, namespace: user.namespace }).execute
begin
#Enable Request store
RequestStore.begin!
Gitlab::ImportExport::ProjectTreeRestorer.new(user: user, shared: shared, project: project).restore
ensure
RequestStore.end!
RequestStore.clear!
end
```
1. In case you need the repository as well, you can restore it using:
```ruby
repo_path = File.join(shared.export_path, Gitlab::ImportExport.project_bundle_filename)
Gitlab::ImportExport::RepoRestorer.new(path_to_bundle: repo_path,
shared: shared,
project: project).restore
```
We are storing all import failures in the `import_failures` data table.
To make sure that the project import finished without any issues, check:
```ruby
project.import_failures.all
```
## Performance testing
For Performance testing, we should:
- Import a quite large project, [`gitlabhq`](https://gitlab.com/gitlab-org/quality/performance-data#gitlab-performance-test-framework-data) should be a good example.
- Measure the execution time of `ProjectTreeRestorer`.
- Count the number of executed SQL queries during the restore.
- Observe the number of GC cycles happening.
You can use this [snippet](https://gitlab.com/gitlab-org/gitlab/snippets/1924954), which will restore the project, and measure the execution time of `ProjectTreeRestorer`, number of SQL queries and number of GC cycles happening.
You can execute the script from the `gdk/gitlab` directory like this:
```sh
bundle exec rails r /path_to_sript/script.rb project_name /path_to_extracted_project request_store_enabled
```
## Troubleshooting
In this section we'll detail any known issues we've seen when trying to import a project and how to manage them.
### Gitaly calls error when importing
If you're attempting to import a large project into a development environment, you may see Gitaly throw an error about too many calls or invocations, for example:
```
Error importing repository into qa-perf-testing/gitlabhq - GitalyClient#call called 31 times from single request. Potential n+1?
```
This is due to a [n+1 calls limit being set for development setups](gitaly.md#toomanyinvocationserror-errors). You can work around this by setting `GITALY_DISABLE_REQUEST_LIMITS=1` as an environment variable, restarting your development environment and importing again.
## Access token setup
Many of the tests also require a GitLab Personal Access Token. This is due to numerous endpoints themselves requiring authentication.
[The official GitLab docs detail how to create this token](../user/profile/personal_access_tokens.md#creating-a-personal-access-token). The tests require that the token is generated by an admin user and that it has the `API` and `read_repository` permissions.
Details on how to use the Access Token with each type of test are found in their respective documentation.
......@@ -47,13 +47,3 @@ and trends between them. For example:
- On [Starter or Bronze tier](https://about.gitlab.com/pricing/) and above.
- By users with Reporter access and above.
## Disable with feature flag
Code Review Analytics is [currently enabled by a feature flag](https://gitlab.com/gitlab-org/gitlab/issues/194165)
that defaults to ON, meaning the feature is available. If you experience performance problems or
otherwise wish to disable the feature, a GitLab administrator can execute a command in a Rails console:
```ruby
Feature.disable(:code_review_analytics)
```
......@@ -15,8 +15,7 @@ Once enabled, click on **Analytics** from the top navigation bar.
From the centralized analytics workspace, the following analytics are available:
- [Code Review Analytics](code_review_analytics.md), enabled with the `code_review_analytics`
[feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-in-development). **(STARTER)**
- [Code Review Analytics](code_review_analytics.md). **(STARTER)**
- [Cycle Analytics](cycle_analytics.md), enabled with the `cycle_analytics`
[feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-in-development). **(PREMIUM)**
- [Productivity Analytics](productivity_analytics.md), enabled with the `productivity_analytics`
......
......@@ -58,14 +58,13 @@ The following languages and dependency managers are supported.
| Java ([Gradle](https://gradle.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
| Java ([Maven](https://maven.apache.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
| JavaScript ([npm](https://www.npmjs.com/), [yarn](https://yarnpkg.com/en/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [Retire.js](https://retirejs.github.io/retire.js/) |
| Go ([Golang](https://golang.org/)) | not currently ([issue](https://gitlab.com/gitlab-org/gitlab/issues/7132 "Dependency Scanning for Go")) | not available |
| PHP ([Composer](https://getcomposer.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
| Python ([pip](https://pip.pypa.io/en/stable/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
| Python ([Pipfile](https://pipenv.kennethreitz.org/en/latest/basics/)) | not currently ([issue](https://gitlab.com/gitlab-org/gitlab/issues/11756 "Pipfile.lock support for Dependency Scanning"))| not available |
| Python ([poetry](https://poetry.eustace.io/)) | not currently ([issue](https://gitlab.com/gitlab-org/gitlab/issues/7006 "Support Poetry in Dependency Scanning")) | not available |
| Ruby ([gem](https://rubygems.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [bundler-audit](https://github.com/rubysec/bundler-audit) |
| Scala ([sbt](https://www.scala-sbt.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
| Go ([go](https://golang.org/)) | yes (alpha) | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
| Go ([Golang](https://golang.org/)) | yes ([alpha](https://gitlab.com/gitlab-org/gitlab/issues/7132)) | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
## Configuration
......
......@@ -52,7 +52,7 @@ The following languages and package managers are supported.
| JavaScript | [Bower](https://bower.io/), [npm](https://www.npmjs.com/), [yarn](https://yarnpkg.com/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| Go | [Godep](https://github.com/tools/godep), go get ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), gvt ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), glide ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), dep ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), trash ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) and govendor ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), [go mod](https://github.com/golang/go/wiki/Modules) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| Java | [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| .NET | [Nuget](https://www.nuget.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| .NET | [Nuget](https://www.nuget.org/) (.NET Framework is supported via the [mono project](https://www.mono-project.com/). Windows specific dependencies are not supported at this time.) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| Python | [pip](https://pip.pypa.io/en/stable/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| Ruby | [gem](https://rubygems.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| Erlang | [rebar](https://www.rebar3.org/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
......
......@@ -54,6 +54,8 @@ this is enabled by default.
Privileged mode is not necessary if you've [disabled Docker in Docker
for SAST](#disabling-docker-in-docker-for-sast)
CAUTION: **Caution:** Our SAST jobs currently expect a Linux container type. Windows containers are not yet supported.
CAUTION: **Caution:**
If you use your own Runners, make sure that the Docker version you have installed
is **not** `19.03.00`. See [troubleshooting information](#error-response-from-daemon-error-processing-tar-file-docker-tar-relocation-error) for details.
......
......@@ -37,11 +37,12 @@ usernames. A GitLab administrator can configure the GitLab instance to
NOTE: **Note:**
In GitLab 11.0, the Master role was renamed to Maintainer.
While Maintainer is the highest project-level role, some actions can only be performed by a personal namespace or group owner.
While Maintainer is the highest project-level role, some actions can only be performed by a personal namespace or group owner,
or an instance admin, who receives all permissions.
The following table depicts the various user permission levels in a project.
| Action | Guest | Reporter | Developer |Maintainer| Owner |
| Action | Guest | Reporter | Developer |Maintainer| Owner* |
|---------------------------------------------------|---------|------------|-------------|----------|--------|
| Download project | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| Leave comments | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
......@@ -138,10 +139,11 @@ The following table depicts the various user permission levels in a project.
| Force push to protected branches (*4*) | | | | | |
| Remove protected branches (*4*) | | | | | |
- (*1*): Guest users are able to perform this action on public and internal projects, but not private projects.
- (*2*): Guest users can only view the confidential issues they created themselves
- (*3*): If **Public pipelines** is enabled in **Project Settings > CI/CD**
- (*4*): Not allowed for Guest, Reporter, Developer, Maintainer, or Owner. See [Protected Branches](./project/protected_branches.md).
\* Owner permission is only available at the group or personal namespace level (and for instance admins) and is inherited by its projects.
(*1*): Guest users are able to perform this action on public and internal projects, but not private projects.
(*2*): Guest users can only view the confidential issues they created themselves.
(*3*): If **Public pipelines** is enabled in **Project Settings > CI/CD**.
(*4*): Not allowed for Guest, Reporter, Developer, Maintainer, or Owner. See [Protected Branches](./project/protected_branches.md).
## Project features permissions
......
......@@ -89,7 +89,7 @@ Some filters can be added multiple times. These include but are not limited to a
![multiple assignees filtering](img/multiple_assignees.png)
### Shortcut
## Shortcut
You'll also find a shortcut on the search field on the top-right of the project's dashboard to
quickly access issues and merge requests created or assigned to you within that project:
......
......@@ -6399,15 +6399,9 @@ msgstr ""
msgid "Deselect all"
msgstr ""
msgid "Design Management"
msgstr ""
msgid "Design Management files and data"
msgstr ""
msgid "Design Sync Not Enabled"
msgstr ""
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
......@@ -8528,9 +8522,6 @@ msgstr ""
msgid "Geo Settings"
msgstr ""
msgid "Geo Troubleshooting"
msgstr ""
msgid "Geo allows you to replicate your GitLab instance to other geographical locations."
msgstr ""
......@@ -10012,9 +10003,6 @@ msgstr ""
msgid "If you believe this may be an error, please refer to the %{linkStart}Geo Troubleshooting%{linkEnd} documentation for more information."
msgstr ""
msgid "If you believe this page to be an error, check out the links below for more information."
msgstr ""
msgid "If you lose your recovery codes you can generate new ones, invalidating all previous codes."
msgstr ""
......
......@@ -14,6 +14,11 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
allow(Projects::ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 }
end
def submit_form
execute_script('document.querySelector(".js-gke-cluster-creation-submit").removeAttribute("disabled")')
execute_script('document.querySelector(".js-gke-cluster-creation-submit").click()')
end
context 'when user has signed with Google' do
let(:project_id) { 'test-project-1234' }
......@@ -34,7 +39,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
end
context 'when user filled form with valid parameters' do
subject { click_button 'Create Kubernetes cluster' }
subject { submit_form }
before do
allow_any_instance_of(GoogleApi::CloudPlatform::Client)
......@@ -47,8 +52,8 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
allow(WaitForClusterCreationWorker).to receive(:perform_in).and_return(nil)
execute_script('document.querySelector(".js-gke-cluster-creation-submit").removeAttribute("disabled")')
sleep 2 # wait for ajax
expect(page).to have_css('.js-gcp-project-id-dropdown')
execute_script('document.querySelector(".js-gcp-project-id-dropdown input").setAttribute("type", "text")')
execute_script('document.querySelector(".js-gcp-zone-dropdown input").setAttribute("type", "text")')
execute_script('document.querySelector(".js-gcp-machine-type-dropdown input").setAttribute("type", "text")')
......@@ -86,8 +91,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
context 'when user filled form with invalid parameters' do
before do
execute_script('document.querySelector(".js-gke-cluster-creation-submit").removeAttribute("disabled")')
click_button 'Create Kubernetes cluster'
submit_form
end
it 'user sees a validation error' do
......
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import GkeSubmitButton from '~/create_cluster/gke_cluster/components/gke_submit_button.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('GkeSubmitButton', () => {
let wrapper;
let store;
let hasValidData;
const buildStore = () =>
new Vuex.Store({
getters: {
hasValidData,
},
});
const buildWrapper = () =>
shallowMount(GkeSubmitButton, {
store,
localVue,
});
const bootstrap = () => {
store = buildStore();
wrapper = buildWrapper();
};
beforeEach(() => {
hasValidData = jest.fn();
});
afterEach(() => {
wrapper.destroy();
});
it('is disabled when hasValidData is false', () => {
hasValidData.mockReturnValueOnce(false);
bootstrap();
expect(wrapper.attributes('disabled')).toBe('disabled');
});
it('is not disabled when hasValidData is true', () => {
hasValidData.mockReturnValueOnce(true);
bootstrap();
expect(wrapper.attributes('disabled')).toBeFalsy();
});
});
import * as getters from '~/create_cluster/gke_cluster/store/getters';
import {
hasProject,
hasZone,
hasMachineType,
hasValidData,
} from '~/create_cluster/gke_cluster/store/getters';
import { selectedProjectMock, selectedZoneMock, selectedMachineTypeMock } from '../mock_data';
describe('GCP Cluster Dropdown Store Getters', () => {
......@@ -7,6 +12,7 @@ describe('GCP Cluster Dropdown Store Getters', () => {
describe('valid states', () => {
beforeEach(() => {
state = {
projectHasBillingEnabled: true,
selectedProject: selectedProjectMock,
selectedZone: selectedZoneMock,
selectedMachineType: selectedMachineTypeMock,
......@@ -15,19 +21,25 @@ describe('GCP Cluster Dropdown Store Getters', () => {
describe('hasProject', () => {
it('should return true when project is selected', () => {
expect(getters.hasProject(state)).toEqual(true);
expect(hasProject(state)).toEqual(true);
});
});
describe('hasZone', () => {
it('should return true when zone is selected', () => {
expect(getters.hasZone(state)).toEqual(true);
expect(hasZone(state)).toEqual(true);
});
});
describe('hasMachineType', () => {
it('should return true when machine type is selected', () => {
expect(getters.hasMachineType(state)).toEqual(true);
expect(hasMachineType(state)).toEqual(true);
});
});
describe('hasValidData', () => {
it('should return true when a project, zone and machine type are selected', () => {
expect(hasValidData(state, { hasZone: true, hasMachineType: true })).toEqual(true);
});
});
});
......@@ -46,19 +58,45 @@ describe('GCP Cluster Dropdown Store Getters', () => {
describe('hasProject', () => {
it('should return false when project is not selected', () => {
expect(getters.hasProject(state)).toEqual(false);
expect(hasProject(state)).toEqual(false);
});
});
describe('hasZone', () => {
it('should return false when zone is not selected', () => {
expect(getters.hasZone(state)).toEqual(false);
expect(hasZone(state)).toEqual(false);
});
});
describe('hasMachineType', () => {
it('should return false when machine type is not selected', () => {
expect(getters.hasMachineType(state)).toEqual(false);
expect(hasMachineType(state)).toEqual(false);
});
});
describe('hasValidData', () => {
let getters;
beforeEach(() => {
getters = { hasZone: true, hasMachineType: true };
});
it('should return false when project is not billable', () => {
state.projectHasBillingEnabled = false;
expect(hasValidData(state, getters)).toEqual(false);
});
it('should return false when zone is not selected', () => {
getters.hasZone = false;
expect(hasValidData(state, getters)).toEqual(false);
});
it('should return false when machine type is not selected', () => {
getters.hasMachineType = false;
expect(hasValidData(state, getters)).toEqual(false);
});
});
});
......
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20200123155929_remove_invalid_jira_data.rb')
describe RemoveInvalidJiraData, :migration do
let(:jira_tracker_data) { table(:jira_tracker_data) }
let(:services) { table(:services) }
let(:service) { services.create(id: 1) }
let(:data) do
{
service_id: service.id,
encrypted_api_url: 'http:url.com',
encrypted_api_url_iv: 'somevalue',
encrypted_url: 'http:url.com',
encrypted_url_iv: 'somevalue',
encrypted_username: 'username',
encrypted_username_iv: 'somevalue',
encrypted_password: 'username',
encrypted_password_iv: 'somevalue'
}
end
let!(:valid_data) { jira_tracker_data.create(data) }
let!(:empty_data) { jira_tracker_data.create(service_id: service.id) }
let!(:invalid_api_url) do
data[:encrypted_api_url_iv] = nil
jira_tracker_data.create(data)
end
let!(:missing_api_url) do
data[:encrypted_api_url] = ''
data[:encrypted_api_url_iv] = nil
jira_tracker_data.create(data)
end
let!(:invalid_url) do
data[:encrypted_url_iv] = nil
jira_tracker_data.create(data)
end
let!(:missing_url) do
data[:encrypted_url] = ''
jira_tracker_data.create(data)
end
let!(:invalid_username) do
data[:encrypted_username_iv] = nil
jira_tracker_data.create(data)
end
let!(:missing_username) do
data[:encrypted_username] = nil
data[:encrypted_username_iv] = nil
jira_tracker_data.create(data)
end
let!(:invalid_password) do
data[:encrypted_password_iv] = nil
jira_tracker_data.create(data)
end
let!(:missing_password) do
data[:encrypted_password] = nil
data[:encrypted_username_iv] = nil
jira_tracker_data.create(data)
end
it 'removes the invalid data' do
valid_data_records = [valid_data, empty_data, missing_api_url, missing_url, missing_username, missing_password]
expect { migrate! }.to change { jira_tracker_data.count }.from(10).to(6)
expect(jira_tracker_data.all).to match_array(valid_data_records)
end
end
......@@ -10,6 +10,10 @@ describe Groups::ImportExport::ExportService do
let(:export_path) { shared.export_path }
let(:service) { described_class.new(group: group, user: user, params: { shared: shared }) }
before do
group.add_owner(user)
end
after do
FileUtils.rm_rf(export_path)
end
......@@ -30,6 +34,18 @@ describe Groups::ImportExport::ExportService do
end
end
context 'when user does not have admin_group permission' do
let!(:another_user) { create(:user) }
let(:service) { described_class.new(group: group, user: another_user, params: { shared: shared }) }
it 'fails' do
expected_message =
"User with ID: %s does not have permission to Group %s with ID: %s." %
[another_user.id, group.name, group.id]
expect { service.execute }.to raise_error(Gitlab::ImportExport::Error).with_message(expected_message)
end
end
context 'when saving services fail' do
before do
allow(service).to receive_message_chain(:tree_exporter, :save).and_return(false)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment