Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-10-02 09:06:28 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2019-10-02 09:06:28 +0300
commit404bb44ef7dfc2b0d4da6b946b8b96007aca4b56 (patch)
treedbc4049f82cb048b471e853c6015ac303981cef9
parentd14219486e0f3b6e642eaeff0862dea169e5d260 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/notifications.gitlab-ci.yml4
-rw-r--r--app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue14
-rw-r--r--doc/api/access_requests.md48
-rw-r--r--doc/development/README.md1
-rw-r--r--doc/development/auto_devops.md42
-rw-r--r--doc/topics/autodevops/index.md18
-rw-r--r--qa/qa/page/merge_request/show.rb24
-rw-r--r--spec/frontend/commit/__snapshots__/commit_pipeline_status_component_spec.js.snap39
-rw-r--r--spec/frontend/commit/commit_pipeline_status_component_spec.js152
-rw-r--r--spec/javascripts/commit/commit_pipeline_status_component_spec.js106
10 files changed, 281 insertions, 167 deletions
diff --git a/.gitlab/ci/notifications.gitlab-ci.yml b/.gitlab/ci/notifications.gitlab-ci.yml
index e4ffceb2dc0..5d7dd752fd5 100644
--- a/.gitlab/ci/notifications.gitlab-ci.yml
+++ b/.gitlab/ci/notifications.gitlab-ci.yml
@@ -11,7 +11,7 @@ schedule:package-and-qa:notify-success:
- .only-canonical-schedules
- .notify
script:
- - 'scripts/notify-slack qa-master ":tada: Scheduled QA against `master` passed! :tada: See $CI_PIPELINE_URL." ci_passing'
+ - 'scripts/notify-slack qa-master ":tada: Scheduled QA against master passed! :tada: See $CI_PIPELINE_URL." ci_passing'
needs: ["schedule:package-and-qa"]
when: on_success
@@ -20,6 +20,6 @@ schedule:package-and-qa:notify-failure:
- .only-canonical-schedules
- .notify
script:
- - 'scripts/notify-slack qa-master ":skull_and_crossbones: Scheduled QA against `master` failed! :skull_and_crossbones: See $CI_PIPELINE_URL." ci_failing'
+ - 'scripts/notify-slack qa-master ":skull_and_crossbones: Scheduled QA against master failed! :skull_and_crossbones: See $CI_PIPELINE_URL." ci_failing'
needs: ["schedule:package-and-qa"]
when: on_failure
diff --git a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
index 12ee1ce2f0c..60fd3ed5ea7 100644
--- a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
+++ b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
@@ -21,14 +21,6 @@ export default {
type: String,
required: true,
},
- /* This prop can be used to replace some of the `render_commit_status`
- used across GitLab, this way we could use this vue component and add a
- realtime status where it makes sense
- realtime: {
- type: Boolean,
- required: false,
- default: true,
- }, */
},
data() {
return {
@@ -47,6 +39,9 @@ export default {
this.service = new CommitPipelineService(this.endpoint);
this.initPolling();
},
+ beforeDestroy() {
+ this.poll.stop();
+ },
methods: {
successCallback(res) {
const { pipelines } = res.data;
@@ -95,9 +90,6 @@ export default {
.catch(this.errorCallback);
},
},
- destroy() {
- this.poll.stop();
- },
};
</script>
<template>
diff --git a/doc/api/access_requests.md b/doc/api/access_requests.md
index 973c3968d90..584a4ecb89c 100644
--- a/doc/api/access_requests.md
+++ b/doc/api/access_requests.md
@@ -6,7 +6,7 @@
The access levels are defined in the `Gitlab::Access` module. Currently, these levels are recognized:
-```
+```plaintext
10 => Guest access
20 => Reporter access
30 => Developer access
@@ -18,14 +18,16 @@
Gets a list of access requests viewable by the authenticated user.
-```
+```plaintext
GET /groups/:id/access_requests
GET /projects/:id/access_requests
```
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| Attribute | Type | Required | Description |
+| --------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+
+Example request:
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/access_requests
@@ -59,14 +61,16 @@ Example response:
Requests access for the authenticated user to a group or project.
-```
+```plaintext
POST /groups/:id/access_requests
POST /projects/:id/access_requests
```
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| Attribute | Type | Required | Description |
+| --------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+
+Example request:
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/access_requests
@@ -90,16 +94,18 @@ Example response:
Approves an access request for the given user.
-```
+```plaintext
PUT /groups/:id/access_requests/:user_id/approve
PUT /projects/:id/access_requests/:user_id/approve
```
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `user_id` | integer | yes | The user ID of the access requester |
-| `access_level` | integer | no | A valid access level (defaults: `30`, developer access level) |
+| Attribute | Type | Required | Description |
+| -------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `user_id` | integer | yes | The user ID of the access requester |
+| `access_level` | integer | no | A valid access level (defaults: `30`, developer access level) |
+
+Example request:
```bash
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/access_requests/:user_id/approve?access_level=20
@@ -123,15 +129,17 @@ Example response:
Denies an access request for the given user.
-```
+```plaintext
DELETE /groups/:id/access_requests/:user_id
DELETE /projects/:id/access_requests/:user_id
```
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `user_id` | integer | yes | The user ID of the access requester |
+| Attribute | Type | Required | Description |
+| --------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `user_id` | integer | yes | The user ID of the access requester |
+
+Example request:
```bash
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/access_requests/:user_id
diff --git a/doc/development/README.md b/doc/development/README.md
index bdc92236716..6480d40303b 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -68,6 +68,7 @@ description: 'Learn how to contribute to GitLab.'
- [Git LFS](lfs.md)
- [Developing against interacting components or features](interacting_components.md)
- [File uploads](uploads.md)
+- [Auto DevOps development guide](auto_devops.md)
## Performance guides
diff --git a/doc/development/auto_devops.md b/doc/development/auto_devops.md
new file mode 100644
index 00000000000..f88bcc9cfb8
--- /dev/null
+++ b/doc/development/auto_devops.md
@@ -0,0 +1,42 @@
+# Auto DevOps development guide
+
+This document provides a development guide for contributors to
+[Auto DevOps](../topics/autodevops/index.md)
+
+## Development
+
+Auto DevOps builds on top of GitLab CI to create an automatic pipeline
+based on your project contents. When Auto DevOps is enabled for a
+project, the user does not need to explicitly include any pipeline configuration
+through a [`.gitlab-ci.yml` file](../ci/yaml/README.md).
+
+In the absence of a `.gitlab-ci.yml` file, the [Auto DevOps CI
+template](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml)
+is used implicitly to configure the pipeline for the project. This
+template is a top-level template that includes other sub-templates,
+which then defines jobs.
+
+Some jobs use images that are built from external projects:
+
+- [Auto Build](../topics/autodevops/index.md#auto-build) uses
+ [configuration](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml)
+ in which the `build` job uses an image that is built using the
+ [`auto-build-image`](https://gitlab.com/gitlab-org/cluster-integration/auto-build-image)
+ project.
+- [Auto Deploy](../topics/autodevops/index.md#auto-deploy) uses
+ [configuration](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml)
+ in which the jobs defined in this template use an image that is built using the
+ [`auto-deploy-image`](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image)
+ project. By default, the Helm chart defined in
+ [`auto-deploy-app`](https://gitlab.com/gitlab-org/charts/auto-deploy-app)
+ is used to deploy.
+
+There are extra variables that get passed to the CI jobs when Auto
+DevOps is enabled that are not present in a normal CI job. These can be
+found in
+[`ProjectAutoDevops`](https://gitlab.com/gitlab-org/gitlab/blob/bf69484afa94e091c3e1383945f60dbe4e8681af/app/models/project_auto_devops.rb).
+
+## Development environment
+
+Configuring [GDK for Auto
+DevOps](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/auto_devops.md).
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 662cc838bdb..802effcb7a2 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -1183,22 +1183,6 @@ As of GitLab 10.0, the supported buildpacks are:
The following restrictions apply.
-### Private project support
-
-CAUTION: **Caution:** Private project support in Auto DevOps is experimental.
-
-When a project has been marked as private, GitLab's [Container
-Registry][container-registry] requires authentication when downloading
-containers. Auto DevOps will automatically provide the required authentication
-information to Kubernetes, allowing temporary access to the registry.
-Authentication credentials will be valid while the pipeline is running, allowing
-for a successful initial deployment.
-
-After the pipeline completes, Kubernetes will no longer be able to access the
-Container Registry. **Restarting a pod, scaling a service, or other actions which
-require on-going access to the registry may fail**. On-going secure access is
-planned for a subsequent release.
-
### Private registry support
There is no documented way of using private container registry with Auto DevOps.
@@ -1274,4 +1258,4 @@ curl --data "value=true" --header "PRIVATE-TOKEN: personal_access_token" https:/
## Development guides
-Configuring [GDK for Auto DevOps](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/auto_devops.md).
+[Development guide for Auto DevOps](../../development/auto_devops.md)
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index ea0cbfe2ab0..6b4a8bacf24 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -129,17 +129,7 @@ module QA
end
def try_to_merge!
- # The merge button is disabled on load
- wait do
- has_element?(:merge_button)
- end
-
- # The merge button is enabled via JS
- wait(reload: false) do
- !find_element(:merge_button).disabled?
- end
-
- merge_immediately
+ merge_immediately if ready_to_merge?
end
def merge!
@@ -187,6 +177,18 @@ module QA
click_element :edit_button
end
+ def ready_to_merge?
+ # The merge button is disabled on load
+ wait do
+ has_element?(:merge_button)
+ end
+
+ # The merge button is enabled via JS
+ wait(reload: false) do
+ !find_element(:merge_button).disabled?
+ end
+ end
+
def view_email_patches
click_element :dropdown_toggle
visit_link_in_element(:download_email_patches)
diff --git a/spec/frontend/commit/__snapshots__/commit_pipeline_status_component_spec.js.snap b/spec/frontend/commit/__snapshots__/commit_pipeline_status_component_spec.js.snap
new file mode 100644
index 00000000000..9199db69fed
--- /dev/null
+++ b/spec/frontend/commit/__snapshots__/commit_pipeline_status_component_spec.js.snap
@@ -0,0 +1,39 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Commit pipeline status component when polling is not successful renders not found CI icon without loader 1`] = `
+<div
+ class="ci-status-link"
+>
+ <a>
+ <ciicon-stub
+ aria-label="Pipeline: not found"
+ cssclasses=""
+ data-container="body"
+ data-original-title="Pipeline: not found"
+ size="24"
+ status="[object Object]"
+ title=""
+ />
+ </a>
+</div>
+`;
+
+exports[`Commit pipeline status component when polling is successful renders CI icon without loader 1`] = `
+<div
+ class="ci-status-link"
+>
+ <a
+ href="/frontend-fixtures/pipelines-project/pipelines/47"
+ >
+ <ciicon-stub
+ aria-label="Pipeline: pending"
+ cssclasses=""
+ data-container="body"
+ data-original-title="Pipeline: pending"
+ size="24"
+ status="[object Object]"
+ title=""
+ />
+ </a>
+</div>
+`;
diff --git a/spec/frontend/commit/commit_pipeline_status_component_spec.js b/spec/frontend/commit/commit_pipeline_status_component_spec.js
new file mode 100644
index 00000000000..1768fd745c9
--- /dev/null
+++ b/spec/frontend/commit/commit_pipeline_status_component_spec.js
@@ -0,0 +1,152 @@
+import Visibility from 'visibilityjs';
+import { GlLoadingIcon } from '@gitlab/ui';
+import Poll from '~/lib/utils/poll';
+import flash from '~/flash';
+import CommitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
+import { shallowMount } from '@vue/test-utils';
+import { getJSONFixture } from '../helpers/fixtures';
+
+jest.mock('~/lib/utils/poll');
+jest.mock('visibilityjs');
+jest.mock('~/flash');
+
+const mockFetchData = jest.fn();
+jest.mock('~/projects/tree/services/commit_pipeline_service', () =>
+ jest.fn().mockImplementation(() => ({
+ fetchData: mockFetchData.mockReturnValue(Promise.resolve()),
+ })),
+);
+
+describe('Commit pipeline status component', () => {
+ let wrapper;
+ const { pipelines } = getJSONFixture('pipelines/pipelines.json');
+ const { status: mockCiStatus } = pipelines[0].details;
+
+ const defaultProps = {
+ endpoint: 'endpoint',
+ };
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(CommitPipelineStatus, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ sync: false,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ jest.clearAllMocks();
+ });
+
+ describe('Visibility management', () => {
+ describe('when component is hidden', () => {
+ beforeEach(() => {
+ Visibility.hidden.mockReturnValue(true);
+ createComponent();
+ });
+
+ it('does not start polling', () => {
+ const [pollInstance] = Poll.mock.instances;
+ expect(pollInstance.makeRequest).not.toHaveBeenCalled();
+ });
+
+ it('requests pipeline data', () => {
+ expect(mockFetchData).toHaveBeenCalled();
+ });
+ });
+
+ describe('when component is visible', () => {
+ beforeEach(() => {
+ Visibility.hidden.mockReturnValue(false);
+ createComponent();
+ });
+
+ it('starts polling', () => {
+ const [pollInstance] = [...Poll.mock.instances].reverse();
+ expect(pollInstance.makeRequest).toHaveBeenCalled();
+ });
+ });
+
+ describe('when component changes its visibility', () => {
+ it.each`
+ visibility | action
+ ${false} | ${'restart'}
+ ${true} | ${'stop'}
+ `(
+ '$action polling when component visibility becomes $visibility',
+ ({ visibility, action }) => {
+ Visibility.hidden.mockReturnValue(!visibility);
+ createComponent();
+ const [pollInstance] = Poll.mock.instances;
+ expect(pollInstance[action]).not.toHaveBeenCalled();
+ Visibility.hidden.mockReturnValue(visibility);
+ const [visibilityHandler] = Visibility.change.mock.calls[0];
+ visibilityHandler();
+ expect(pollInstance[action]).toHaveBeenCalled();
+ },
+ );
+ });
+ });
+
+ it('stops polling when component is destroyed', () => {
+ createComponent();
+ wrapper.destroy();
+ const [pollInstance] = Poll.mock.instances;
+ expect(pollInstance.stop).toHaveBeenCalled();
+ });
+
+ describe('when polling', () => {
+ let pollConfig;
+ beforeEach(() => {
+ Poll.mockImplementation(config => {
+ pollConfig = config;
+ return { makeRequest: jest.fn(), restart: jest.fn(), stop: jest.fn() };
+ });
+ createComponent();
+ });
+
+ it('shows the loading icon at start', () => {
+ createComponent();
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+
+ pollConfig.successCallback({
+ data: { pipelines: [] },
+ });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
+ });
+ });
+
+ describe('is successful', () => {
+ beforeEach(() => {
+ pollConfig.successCallback({
+ data: { pipelines: [{ details: { status: mockCiStatus } }] },
+ });
+ return wrapper.vm.$nextTick();
+ });
+
+ it('renders CI icon without loader', () => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+
+ describe('is not successful', () => {
+ beforeEach(() => {
+ pollConfig.errorCallback();
+ });
+
+ it('renders not found CI icon without loader', () => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('displays flash error message', () => {
+ expect(flash).toHaveBeenCalled();
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/commit/commit_pipeline_status_component_spec.js b/spec/javascripts/commit/commit_pipeline_status_component_spec.js
deleted file mode 100644
index f6b36e88a5f..00000000000
--- a/spec/javascripts/commit/commit_pipeline_status_component_spec.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import Vue from 'vue';
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-
-describe('Commit pipeline status component', () => {
- let vm;
- let Component;
- let mock;
- const mockCiStatus = {
- details_path: '/root/hello-world/pipelines/1',
- favicon: 'canceled.ico',
- group: 'canceled',
- has_details: true,
- icon: 'status_canceled',
- label: 'canceled',
- text: 'canceled',
- };
-
- beforeEach(() => {
- Component = Vue.extend(commitPipelineStatus);
- });
-
- describe('While polling pipeline data successfully', () => {
- beforeEach(() => {
- mock = new MockAdapter(axios);
- mock.onGet('/dummy/endpoint').reply(() => {
- const res = Promise.resolve([
- 200,
- {
- pipelines: [
- {
- details: {
- status: mockCiStatus,
- },
- },
- ],
- },
- ]);
- return res;
- });
- vm = mountComponent(Component, {
- endpoint: '/dummy/endpoint',
- });
- });
-
- afterEach(() => {
- vm.poll.stop();
- vm.$destroy();
- mock.restore();
- });
-
- it('shows the loading icon when polling is starting', done => {
- expect(vm.$el.querySelector('.loading-container')).not.toBe(null);
- setTimeout(() => {
- expect(vm.$el.querySelector('.loading-container')).toBe(null);
- done();
- });
- });
-
- it('contains a ciStatus when the polling is successful ', done => {
- setTimeout(() => {
- expect(vm.ciStatus).toEqual(mockCiStatus);
- done();
- });
- });
-
- it('contains a ci-status icon when polling is successful', done => {
- setTimeout(() => {
- expect(vm.$el.querySelector('.ci-status-icon')).not.toBe(null);
- expect(vm.$el.querySelector('.ci-status-icon').classList).toContain(
- `ci-status-icon-${mockCiStatus.group}`,
- );
- done();
- });
- });
- });
-
- describe('When polling data was not successful', () => {
- beforeEach(() => {
- mock = new MockAdapter(axios);
- mock.onGet('/dummy/endpoint').reply(502, {});
- vm = new Component({
- props: {
- endpoint: '/dummy/endpoint',
- },
- });
- });
-
- afterEach(() => {
- vm.poll.stop();
- vm.$destroy();
- mock.restore();
- });
-
- it('calls an errorCallback', done => {
- spyOn(vm, 'errorCallback').and.callThrough();
- vm.$mount();
- setTimeout(() => {
- expect(vm.errorCallback.calls.count()).toEqual(1);
- done();
- });
- });
- });
-});