Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
2fc7740f3c
commit
2c15256184
27 changed files with 526 additions and 53 deletions
|
@ -249,15 +249,22 @@ export default {
|
|||
createFlash(s__('Pipelines|Something went wrong while cleaning runners cache.'));
|
||||
});
|
||||
},
|
||||
resetRequestData() {
|
||||
this.requestData = { page: this.page, scope: this.scope };
|
||||
},
|
||||
filterPipelines(filters) {
|
||||
this.resetRequestData();
|
||||
|
||||
filters.forEach(filter => {
|
||||
this.requestData[filter.type] = filter.value.data;
|
||||
// do not add Any for username query param, so we
|
||||
// can fetch all trigger authors
|
||||
if (filter.value.data !== ANY_TRIGGER_AUTHOR) {
|
||||
this.requestData[filter.type] = filter.value.data;
|
||||
}
|
||||
});
|
||||
|
||||
// set query params back to default if filtering by Any author
|
||||
// or input is cleared on submit
|
||||
if (this.requestData.username === ANY_TRIGGER_AUTHOR || filters.length === 0) {
|
||||
this.requestData = { page: this.page, scope: this.scope };
|
||||
if (filters.length === 0) {
|
||||
this.resetRequestData();
|
||||
}
|
||||
|
||||
this.updateContent(this.requestData);
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
import { GlFilteredSearch } from '@gitlab/ui';
|
||||
import { __, s__ } from '~/locale';
|
||||
import PipelineTriggerAuthorToken from './tokens/pipeline_trigger_author_token.vue';
|
||||
import PipelineBranchNameToken from './tokens/pipeline_branch_name_token.vue';
|
||||
import Api from '~/api';
|
||||
import createFlash from '~/flash';
|
||||
import { FETCH_AUTHOR_ERROR_MESSAGE, FETCH_BRANCH_ERROR_MESSAGE } from '../constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -22,6 +24,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
projectUsers: null,
|
||||
projectBranches: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -31,11 +34,21 @@ export default {
|
|||
type: 'username',
|
||||
icon: 'user',
|
||||
title: s__('Pipeline|Trigger author'),
|
||||
dataType: 'username',
|
||||
unique: true,
|
||||
token: PipelineTriggerAuthorToken,
|
||||
operators: [{ value: '=', description: __('is'), default: 'true' }],
|
||||
triggerAuthors: this.projectUsers,
|
||||
projectId: this.projectId,
|
||||
},
|
||||
{
|
||||
type: 'ref',
|
||||
icon: 'branch',
|
||||
title: s__('Pipeline|Branch name'),
|
||||
unique: true,
|
||||
token: PipelineBranchNameToken,
|
||||
operators: [{ value: '=', description: __('is'), default: 'true' }],
|
||||
branches: this.projectBranches,
|
||||
projectId: this.projectId,
|
||||
},
|
||||
];
|
||||
},
|
||||
|
@ -46,7 +59,16 @@ export default {
|
|||
this.projectUsers = users;
|
||||
})
|
||||
.catch(err => {
|
||||
createFlash(__('There was a problem fetching project users.'));
|
||||
createFlash(FETCH_AUTHOR_ERROR_MESSAGE);
|
||||
throw err;
|
||||
});
|
||||
|
||||
Api.branches(this.projectId)
|
||||
.then(({ data }) => {
|
||||
this.projectBranches = data.map(branch => branch.name);
|
||||
})
|
||||
.catch(err => {
|
||||
createFlash(FETCH_BRANCH_ERROR_MESSAGE);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
<script>
|
||||
import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
|
||||
import Api from '~/api';
|
||||
import { FETCH_BRANCH_ERROR_MESSAGE, FILTER_PIPELINES_SEARCH_DELAY } from '../../constants';
|
||||
import createFlash from '~/flash';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlFilteredSearchToken,
|
||||
GlFilteredSearchSuggestion,
|
||||
GlLoadingIcon,
|
||||
},
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
value: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
branches: this.config.branches,
|
||||
loading: true,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
fetchBranchBySearchTerm(searchTerm) {
|
||||
Api.branches(this.config.projectId, searchTerm)
|
||||
.then(res => {
|
||||
this.branches = res.data.map(branch => branch.name);
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(err => {
|
||||
createFlash(FETCH_BRANCH_ERROR_MESSAGE);
|
||||
this.loading = false;
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
searchBranches: debounce(function debounceSearch({ data }) {
|
||||
this.fetchBranchBySearchTerm(data);
|
||||
}, FILTER_PIPELINES_SEARCH_DELAY),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-filtered-search-token
|
||||
:config="config"
|
||||
v-bind="{ ...$props, ...$attrs }"
|
||||
v-on="$listeners"
|
||||
@input="searchBranches"
|
||||
>
|
||||
<template #suggestions>
|
||||
<gl-loading-icon v-if="loading" />
|
||||
<template v-else>
|
||||
<gl-filtered-search-suggestion
|
||||
v-for="(branch, index) in branches"
|
||||
:key="index"
|
||||
:value="branch"
|
||||
>
|
||||
{{ branch }}
|
||||
</gl-filtered-search-suggestion>
|
||||
</template>
|
||||
</template>
|
||||
</gl-filtered-search-token>
|
||||
</template>
|
|
@ -4,8 +4,16 @@ import {
|
|||
GlAvatar,
|
||||
GlFilteredSearchSuggestion,
|
||||
GlDropdownDivider,
|
||||
GlLoadingIcon,
|
||||
} from '@gitlab/ui';
|
||||
import { ANY_TRIGGER_AUTHOR } from '../../constants';
|
||||
import Api from '~/api';
|
||||
import createFlash from '~/flash';
|
||||
import { debounce } from 'lodash';
|
||||
import {
|
||||
ANY_TRIGGER_AUTHOR,
|
||||
FETCH_AUTHOR_ERROR_MESSAGE,
|
||||
FILTER_PIPELINES_SEARCH_DELAY,
|
||||
} from '../../constants';
|
||||
|
||||
export default {
|
||||
anyTriggerAuthor: ANY_TRIGGER_AUTHOR,
|
||||
|
@ -14,6 +22,7 @@ export default {
|
|||
GlAvatar,
|
||||
GlFilteredSearchSuggestion,
|
||||
GlDropdownDivider,
|
||||
GlLoadingIcon,
|
||||
},
|
||||
props: {
|
||||
config: {
|
||||
|
@ -25,26 +34,49 @@ export default {
|
|||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
users: this.config.triggerAuthors,
|
||||
loading: true,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
currentValue() {
|
||||
return this.value.data.toLowerCase();
|
||||
},
|
||||
filteredTriggerAuthors() {
|
||||
return this.config.triggerAuthors.filter(user => {
|
||||
return user.username.toLowerCase().includes(this.currentValue);
|
||||
});
|
||||
},
|
||||
activeUser() {
|
||||
return this.config.triggerAuthors.find(user => {
|
||||
return this.users.find(user => {
|
||||
return user.username.toLowerCase() === this.currentValue;
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
fetchAuthorBySearchTerm(searchTerm) {
|
||||
Api.projectUsers(this.config.projectId, searchTerm)
|
||||
.then(res => {
|
||||
this.users = res;
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(err => {
|
||||
createFlash(FETCH_AUTHOR_ERROR_MESSAGE);
|
||||
this.loading = false;
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
searchAuthors: debounce(function debounceSearch({ data }) {
|
||||
this.fetchAuthorBySearchTerm(data);
|
||||
}, FILTER_PIPELINES_SEARCH_DELAY),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-filtered-search-token :config="config" v-bind="{ ...$props, ...$attrs }" v-on="$listeners">
|
||||
<gl-filtered-search-token
|
||||
:config="config"
|
||||
v-bind="{ ...$props, ...$attrs }"
|
||||
v-on="$listeners"
|
||||
@input="searchAuthors"
|
||||
>
|
||||
<template #view="{inputValue}">
|
||||
<gl-avatar
|
||||
v-if="activeUser"
|
||||
|
@ -60,19 +92,23 @@ export default {
|
|||
$options.anyTriggerAuthor
|
||||
}}</gl-filtered-search-suggestion>
|
||||
<gl-dropdown-divider />
|
||||
<gl-filtered-search-suggestion
|
||||
v-for="user in filteredTriggerAuthors"
|
||||
:key="user.username"
|
||||
:value="user.username"
|
||||
>
|
||||
<div class="d-flex">
|
||||
<gl-avatar :size="32" :src="user.avatar_url" />
|
||||
<div>
|
||||
<div>{{ user.name }}</div>
|
||||
<div>@{{ user.username }}</div>
|
||||
|
||||
<gl-loading-icon v-if="loading" />
|
||||
<template v-else>
|
||||
<gl-filtered-search-suggestion
|
||||
v-for="user in users"
|
||||
:key="user.username"
|
||||
:value="user.username"
|
||||
>
|
||||
<div class="d-flex">
|
||||
<gl-avatar :size="32" :src="user.avatar_url" />
|
||||
<div>
|
||||
<div>{{ user.name }}</div>
|
||||
<div>@{{ user.username }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</gl-filtered-search-suggestion>
|
||||
</gl-filtered-search-suggestion>
|
||||
</template>
|
||||
</template>
|
||||
</gl-filtered-search-token>
|
||||
</template>
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { __ } from '~/locale';
|
||||
|
||||
export const CANCEL_REQUEST = 'CANCEL_REQUEST';
|
||||
export const PIPELINES_TABLE = 'PIPELINES_TABLE';
|
||||
export const LAYOUT_CHANGE_DELAY = 300;
|
||||
export const FILTER_PIPELINES_SEARCH_DELAY = 200;
|
||||
export const ANY_TRIGGER_AUTHOR = 'Any';
|
||||
|
||||
export const TestStatus = {
|
||||
|
@ -8,3 +11,6 @@ export const TestStatus = {
|
|||
SKIPPED: 'skipped',
|
||||
SUCCESS: 'success',
|
||||
};
|
||||
|
||||
export const FETCH_AUTHOR_ERROR_MESSAGE = __('There was a problem fetching project users.');
|
||||
export const FETCH_BRANCH_ERROR_MESSAGE = __('There was a problem fetching project branches.');
|
||||
|
|
|
@ -19,7 +19,7 @@ export default class PipelinesService {
|
|||
}
|
||||
|
||||
getPipelines(data = {}) {
|
||||
const { scope, page, username } = data;
|
||||
const { scope, page, username, ref } = data;
|
||||
const { CancelToken } = axios;
|
||||
|
||||
const queryParams = { scope, page };
|
||||
|
@ -28,6 +28,10 @@ export default class PipelinesService {
|
|||
queryParams.username = username;
|
||||
}
|
||||
|
||||
if (ref) {
|
||||
queryParams.ref = ref;
|
||||
}
|
||||
|
||||
this.cancelationSource = CancelToken.source();
|
||||
|
||||
return axios.get(this.endpoint, {
|
||||
|
|
|
@ -35,13 +35,18 @@ export default {
|
|||
},
|
||||
|
||||
onChangeWithFilter(params) {
|
||||
const { username } = this.requestData;
|
||||
const { username, ref } = this.requestData;
|
||||
const paramsData = params;
|
||||
|
||||
if (username) {
|
||||
return { ...params, username };
|
||||
paramsData.username = username;
|
||||
}
|
||||
|
||||
return params;
|
||||
if (ref) {
|
||||
paramsData.ref = ref;
|
||||
}
|
||||
|
||||
return paramsData;
|
||||
},
|
||||
|
||||
updateInternalState(parameters) {
|
||||
|
|
|
@ -12,7 +12,7 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
|
||||
before_action do
|
||||
push_frontend_feature_flag(:junit_pipeline_view)
|
||||
push_frontend_feature_flag(:filter_pipelines_search)
|
||||
push_frontend_feature_flag(:filter_pipelines_search, default_enabled: true)
|
||||
push_frontend_feature_flag(:dag_pipeline_tab)
|
||||
end
|
||||
before_action :ensure_pipeline, only: [:show]
|
||||
|
@ -269,7 +269,7 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def index_params
|
||||
params.permit(:scope, :username)
|
||||
params.permit(:scope, :username, :ref)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -17,6 +17,17 @@ module ClustersHelper
|
|||
end
|
||||
end
|
||||
|
||||
def provider_icon(provider = nil)
|
||||
case provider
|
||||
when 'aws'
|
||||
image_tag 'illustrations/logos/amazon_eks.svg', alt: s_('ClusterIntegration|Amazon EKS'), class: 'gl-h-full'
|
||||
when 'gcp'
|
||||
image_tag 'illustrations/logos/google_gke.svg', alt: s_('ClusterIntegration|Google GKE'), class: 'gl-h-full'
|
||||
else
|
||||
image_tag 'illustrations/logos/kubernetes.svg', alt: _('Kubernetes Cluster'), class: 'gl-h-full'
|
||||
end
|
||||
end
|
||||
|
||||
def render_gcp_signup_offer
|
||||
return if Gitlab::CurrentSettings.current_application_settings.hide_third_party_offers?
|
||||
return unless show_gcp_signup_offer?
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Placeholder class for model that is implemented in EE
|
||||
# It reserves '&' as a reference prefix, but the table does not exists in CE
|
||||
# It reserves '&' as a reference prefix, but the table does not exist in FOSS
|
||||
class Epic < ApplicationRecord
|
||||
include IgnorableColumns
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
.card-body.gl-responsive-table-row
|
||||
.table-section.section-60
|
||||
.table-mobile-header{ role: "rowheader" }= s_("ClusterIntegration|Kubernetes cluster")
|
||||
.table-mobile-content
|
||||
.table-mobile-content.gl-display-flex.gl-align-items-center.gl-justify-content-end.gl-justify-content-md-start
|
||||
.gl-w-6.gl-h-6.gl-mr-3.gl-display-flex.gl-align-items-center= provider_icon(cluster.provider_type)
|
||||
= cluster.item_link(clusterable, html_options: { data: { qa_selector: 'cluster', qa_cluster_name: cluster.name } })
|
||||
- if cluster.status_name == :creating
|
||||
.spinner.ml-2.align-middle.has-tooltip{ title: s_("ClusterIntegration|Cluster being created") }
|
||||
|
|
5
changelogs/unreleased/208223-provider-icon-haml.yml
Normal file
5
changelogs/unreleased/208223-provider-icon-haml.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Added provider icon to cluster index display
|
||||
merge_request: 31134
|
||||
author:
|
||||
type: added
|
5
changelogs/unreleased/filter-pipeline-by-branch.yml
Normal file
5
changelogs/unreleased/filter-pipeline-by-branch.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Filter pipelines by trigger author and branch name
|
||||
merge_request: 31386
|
||||
author:
|
||||
type: added
|
|
@ -314,7 +314,7 @@ It is important to note that selective synchronization:
|
|||
Selective synchronization restrictions are implemented on the **secondary** nodes,
|
||||
not the **primary** node.
|
||||
|
||||
### Git operations on unreplicated respositories
|
||||
### Git operations on unreplicated repositories
|
||||
|
||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2562) in GitLab 12.10 for HTTP(S) and in GitLab 13.0 for SSH.
|
||||
|
||||
|
|
|
@ -195,12 +195,12 @@ authentication](https://gitlab.com/gitlab-org/gitaly/blob/master/doc/configurati
|
|||
gitlab_workhorse['enable'] = false
|
||||
grafana['enable'] = false
|
||||
|
||||
# If you run a seperate monitoring node you can disable these services
|
||||
# If you run a separate monitoring node you can disable these services
|
||||
alertmanager['enable'] = false
|
||||
prometheus['enable'] = false
|
||||
|
||||
# If you don't run a seperate monitoring node you can
|
||||
# Enable Prometheus access & disable these extra services
|
||||
# If you don't run a separate monitoring node you can
|
||||
# enable Prometheus access & disable these extra services.
|
||||
# This makes Prometheus listen on all interfaces. You must use firewalls to restrict access to this address/port.
|
||||
# prometheus['listen_address'] = '0.0.0.0:9090'
|
||||
# prometheus['monitor_kubernetes'] = false
|
||||
|
|
|
@ -21,6 +21,15 @@ Pipeline schedules can be used to also run [pipelines](index.md) at specific int
|
|||
In addition to using the GitLab UI, pipeline schedules can be maintained using the
|
||||
[Pipeline schedules API](../../api/pipeline_schedules.md).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
In order for a scheduled pipeline to be created successfully:
|
||||
|
||||
- The schedule owner must have [permissions](../../user/permissions.md) to merge into the target branch.
|
||||
- The pipeline configuration must be valid.
|
||||
|
||||
Otherwise the pipeline is not created.
|
||||
|
||||
## Configuring pipeline schedules
|
||||
|
||||
To schedule a pipeline for project:
|
||||
|
|
|
@ -180,7 +180,7 @@ using environment variables.
|
|||
| `CLAIR_VULNERABILITIES_DB_URL` | (**DEPRECATED - use `CLAIR_DB_CONNECTION_STRING` instead**) This variable is explicitly set in the [services section](https://gitlab.com/gitlab-org/gitlab/-/blob/898c5da43504eba87b749625da50098d345b60d6/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml#L23) of the `Container-Scanning.gitlab-ci.yml` file and defaults to `clair-vulnerabilities-db`. This value represents the address that the [PostgreSQL server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db) is running on and **shouldn't be changed** unless you're running the image locally as described in the [Running the standalone Container Scanning Tool](#running-the-standalone-container-scanning-tool) section. | `clair-vulnerabilities-db` |
|
||||
| `CLAIR_DB_CONNECTION_STRING` | This variable represents the [connection string](https://www.postgresql.org/docs/9.3/libpq-connect.html#AEN39692) to the [PostgreSQL server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db) database and **shouldn't be changed** unless you're running the image locally as described in the [Running the standalone Container Scanning Tool](#running-the-standalone-container-scanning-tool) section. The host value for the connection string must match the [alias](https://gitlab.com/gitlab-org/gitlab/-/blob/898c5da43504eba87b749625da50098d345b60d6/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml#L23) value of the `Container-Scanning.gitlab-ci.yml` template file, which defaults to `clair-vulnerabilities-db`. | `postgresql://postgres:password@clair-vulnerabilities-db:5432/postgres?sslmode=disable&statement_timeout=60000` |
|
||||
| `CI_APPLICATION_REPOSITORY` | Docker repository URL for the image to be scanned. | `$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG` |
|
||||
| `CI_APPLICATION_TAG` | Docker respository tag for the image to be scanned. | `$CI_COMMIT_SHA` |
|
||||
| `CI_APPLICATION_TAG` | Docker repository tag for the image to be scanned. | `$CI_COMMIT_SHA` |
|
||||
| `CLAIR_DB_IMAGE` | The Docker image name and tag for the [PostgreSQL server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db). It can be useful to override this value with a specific version, for example, to provide a consistent set of vulnerabilities for integration testing purposes, or to refer to a locally hosted vulnerabilities database for an on-premise offline installation. | `arminc/clair-db:latest` |
|
||||
| `CLAIR_DB_IMAGE_TAG` | (**DEPRECATED - use `CLAIR_DB_IMAGE` instead**) The Docker image tag for the [PostgreSQL server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db). It can be useful to override this value with a specific version, for example, to provide a consistent set of vulnerabilities for integration testing purposes. | `latest` |
|
||||
| `DOCKERFILE_PATH` | The path to the `Dockerfile` to be used for generating remediations. By default, the scanner will look for a file named `Dockerfile` in the root directory of the project, so this variable should only be configured if your `Dockerfile` is in a non-standard location, such as a subdirectory. See [Solutions for vulnerabilities](#solutions-for-vulnerabilities-auto-remediation) for more details. | `Dockerfile` |
|
||||
|
|
|
@ -18,6 +18,11 @@ measuring the accessibility of web sites, and has built a simple
|
|||
This job outputs accessibility violations, warnings, and notices for each page
|
||||
analyzed to a file called `accessibility`.
|
||||
|
||||
[Since GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/39425), in addition to the report artifact that is created, GitLab will also show the
|
||||
Accessibility Report in the merge request widget area:
|
||||
|
||||
![Accessibility Merge Request Widget](img/accessibility_mr_widget_v13_0.png)
|
||||
|
||||
## Configure Accessibility Testing
|
||||
|
||||
This example shows how to run [pa11y](https://pa11y.org/)
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 127 KiB |
|
@ -15237,6 +15237,9 @@ msgstr ""
|
|||
msgid "Pipelines|parent"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipeline|Branch name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipeline|Commit"
|
||||
msgstr ""
|
||||
|
||||
|
@ -21292,6 +21295,9 @@ msgstr ""
|
|||
msgid "There was a problem communicating with your device."
|
||||
msgstr ""
|
||||
|
||||
msgid "There was a problem fetching project branches."
|
||||
msgstr ""
|
||||
|
||||
msgid "There was a problem fetching project users."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -195,6 +195,26 @@ describe Projects::PipelinesController do
|
|||
end
|
||||
end
|
||||
|
||||
context 'filter by ref' do
|
||||
let!(:pipeline) { create(:ci_pipeline, :running, project: project, ref: 'branch-1') }
|
||||
|
||||
context 'when pipelines with the ref exists' do
|
||||
it 'returns matched pipelines' do
|
||||
get_pipelines_index_json(ref: 'branch-1')
|
||||
|
||||
check_pipeline_response(returned: 1, all: 1, running: 1, pending: 0, finished: 0)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no pipeline with the ref exists' do
|
||||
it 'returns empty list' do
|
||||
get_pipelines_index_json(ref: 'invalid-ref')
|
||||
|
||||
check_pipeline_response(returned: 0, all: 0, running: 0, pending: 0, finished: 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_pipelines_index_json(params = {})
|
||||
get :index, params: {
|
||||
namespace_id: project.namespace,
|
||||
|
|
|
@ -3,7 +3,13 @@ import { mount } from '@vue/test-utils';
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import PipelinesFilteredSearch from '~/pipelines/components/pipelines_filtered_search.vue';
|
||||
import { users, mockSearch, pipelineWithStages } from '../mock_data';
|
||||
import {
|
||||
users,
|
||||
mockSearch,
|
||||
pipelineWithStages,
|
||||
branches,
|
||||
mockBranchesAfterMap,
|
||||
} from '../mock_data';
|
||||
import { GlFilteredSearch } from '@gitlab/ui';
|
||||
|
||||
describe('Pipelines filtered search', () => {
|
||||
|
@ -30,6 +36,7 @@ describe('Pipelines filtered search', () => {
|
|||
mock = new MockAdapter(axios);
|
||||
|
||||
jest.spyOn(Api, 'projectUsers').mockResolvedValue(users);
|
||||
jest.spyOn(Api, 'branches').mockResolvedValue({ data: branches });
|
||||
|
||||
createComponent();
|
||||
});
|
||||
|
@ -52,9 +59,19 @@ describe('Pipelines filtered search', () => {
|
|||
type: 'username',
|
||||
icon: 'user',
|
||||
title: 'Trigger author',
|
||||
dataType: 'username',
|
||||
unique: true,
|
||||
triggerAuthors: users,
|
||||
projectId: '21',
|
||||
operators: [expect.objectContaining({ value: '=' })],
|
||||
});
|
||||
|
||||
expect(getSearchToken('ref')).toMatchObject({
|
||||
type: 'ref',
|
||||
icon: 'branch',
|
||||
title: 'Branch name',
|
||||
unique: true,
|
||||
branches: mockBranchesAfterMap,
|
||||
projectId: '21',
|
||||
operators: [expect.objectContaining({ value: '=' })],
|
||||
});
|
||||
});
|
||||
|
@ -65,6 +82,12 @@ describe('Pipelines filtered search', () => {
|
|||
expect(wrapper.vm.projectUsers).toEqual(users);
|
||||
});
|
||||
|
||||
it('fetches and sets branches', () => {
|
||||
expect(Api.branches).toHaveBeenCalled();
|
||||
|
||||
expect(wrapper.vm.projectBranches).toEqual(mockBranchesAfterMap);
|
||||
});
|
||||
|
||||
it('emits filterPipelines on submit with correct filter', () => {
|
||||
findFilteredSearch().vm.$emit('submit', mockSearch);
|
||||
|
||||
|
|
|
@ -479,4 +479,90 @@ export const users = [
|
|||
},
|
||||
];
|
||||
|
||||
export const mockSearch = { type: 'username', value: { data: 'root', operator: '=' } };
|
||||
export const branches = [
|
||||
{
|
||||
name: 'branch-1',
|
||||
commit: {
|
||||
id: '21fb056cc47dcf706670e6de635b1b326490ebdc',
|
||||
short_id: '21fb056c',
|
||||
created_at: '2020-05-07T10:58:28.000-04:00',
|
||||
parent_ids: null,
|
||||
title: 'Add new file',
|
||||
message: 'Add new file',
|
||||
author_name: 'Administrator',
|
||||
author_email: 'admin@example.com',
|
||||
authored_date: '2020-05-07T10:58:28.000-04:00',
|
||||
committer_name: 'Administrator',
|
||||
committer_email: 'admin@example.com',
|
||||
committed_date: '2020-05-07T10:58:28.000-04:00',
|
||||
web_url:
|
||||
'http://192.168.1.22:3000/root/dag-pipeline/-/commit/21fb056cc47dcf706670e6de635b1b326490ebdc',
|
||||
},
|
||||
merged: false,
|
||||
protected: false,
|
||||
developers_can_push: false,
|
||||
developers_can_merge: false,
|
||||
can_push: true,
|
||||
default: false,
|
||||
web_url: 'http://192.168.1.22:3000/root/dag-pipeline/-/tree/branch-1',
|
||||
},
|
||||
{
|
||||
name: 'branch-10',
|
||||
commit: {
|
||||
id: '66673b07efef254dab7d537f0433a40e61cf84fe',
|
||||
short_id: '66673b07',
|
||||
created_at: '2020-03-16T11:04:46.000-04:00',
|
||||
parent_ids: null,
|
||||
title: 'Update .gitlab-ci.yml',
|
||||
message: 'Update .gitlab-ci.yml',
|
||||
author_name: 'Administrator',
|
||||
author_email: 'admin@example.com',
|
||||
authored_date: '2020-03-16T11:04:46.000-04:00',
|
||||
committer_name: 'Administrator',
|
||||
committer_email: 'admin@example.com',
|
||||
committed_date: '2020-03-16T11:04:46.000-04:00',
|
||||
web_url:
|
||||
'http://192.168.1.22:3000/root/dag-pipeline/-/commit/66673b07efef254dab7d537f0433a40e61cf84fe',
|
||||
},
|
||||
merged: false,
|
||||
protected: false,
|
||||
developers_can_push: false,
|
||||
developers_can_merge: false,
|
||||
can_push: true,
|
||||
default: false,
|
||||
web_url: 'http://192.168.1.22:3000/root/dag-pipeline/-/tree/branch-10',
|
||||
},
|
||||
{
|
||||
name: 'branch-11',
|
||||
commit: {
|
||||
id: '66673b07efef254dab7d537f0433a40e61cf84fe',
|
||||
short_id: '66673b07',
|
||||
created_at: '2020-03-16T11:04:46.000-04:00',
|
||||
parent_ids: null,
|
||||
title: 'Update .gitlab-ci.yml',
|
||||
message: 'Update .gitlab-ci.yml',
|
||||
author_name: 'Administrator',
|
||||
author_email: 'admin@example.com',
|
||||
authored_date: '2020-03-16T11:04:46.000-04:00',
|
||||
committer_name: 'Administrator',
|
||||
committer_email: 'admin@example.com',
|
||||
committed_date: '2020-03-16T11:04:46.000-04:00',
|
||||
web_url:
|
||||
'http://192.168.1.22:3000/root/dag-pipeline/-/commit/66673b07efef254dab7d537f0433a40e61cf84fe',
|
||||
},
|
||||
merged: false,
|
||||
protected: false,
|
||||
developers_can_push: false,
|
||||
developers_can_merge: false,
|
||||
can_push: true,
|
||||
default: false,
|
||||
web_url: 'http://192.168.1.22:3000/root/dag-pipeline/-/tree/branch-11',
|
||||
},
|
||||
];
|
||||
|
||||
export const mockSearch = [
|
||||
{ type: 'username', value: { data: 'root', operator: '=' } },
|
||||
{ type: 'ref', value: { data: 'master', operator: '=' } },
|
||||
];
|
||||
|
||||
export const mockBranchesAfterMap = ['branch-1', 'branch-10', 'branch-11'];
|
||||
|
|
|
@ -5,7 +5,7 @@ import axios from '~/lib/utils/axios_utils';
|
|||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import PipelinesComponent from '~/pipelines/components/pipelines.vue';
|
||||
import Store from '~/pipelines/stores/pipelines_store';
|
||||
import { pipelineWithStages, stageReply, users, mockSearch } from './mock_data';
|
||||
import { pipelineWithStages, stageReply, users, mockSearch, branches } from './mock_data';
|
||||
import { GlFilteredSearch } from '@gitlab/ui';
|
||||
|
||||
describe('Pipelines', () => {
|
||||
|
@ -63,7 +63,9 @@ describe('Pipelines', () => {
|
|||
beforeEach(() => {
|
||||
mock = new MockAdapter(axios);
|
||||
pipelines = getJSONFixture(jsonFixtureName);
|
||||
|
||||
jest.spyOn(Api, 'projectUsers').mockResolvedValue(users);
|
||||
jest.spyOn(Api, 'branches').mockResolvedValue({ data: branches });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -674,9 +676,9 @@ describe('Pipelines', () => {
|
|||
|
||||
it('updates request data and query params on filter submit', () => {
|
||||
const updateContentMock = jest.spyOn(wrapper.vm, 'updateContent');
|
||||
const expectedQueryParams = { page: '1', scope: 'all', username: 'root' };
|
||||
const expectedQueryParams = { page: '1', scope: 'all', username: 'root', ref: 'master' };
|
||||
|
||||
findFilteredSearch().vm.$emit('submit', [mockSearch]);
|
||||
findFilteredSearch().vm.$emit('submit', mockSearch);
|
||||
|
||||
expect(wrapper.vm.requestData).toEqual(expectedQueryParams);
|
||||
expect(updateContentMock).toHaveBeenCalledWith(expectedQueryParams);
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import PipelineBranchNameToken from '~/pipelines/components/tokens/pipeline_branch_name_token.vue';
|
||||
import { branches } from '../mock_data';
|
||||
|
||||
describe('Pipeline Branch Name Token', () => {
|
||||
let wrapper;
|
||||
|
||||
const findFilteredSearchToken = () => wrapper.find(GlFilteredSearchToken);
|
||||
const findAllFilteredSearchSuggestions = () => wrapper.findAll(GlFilteredSearchSuggestion);
|
||||
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
|
||||
|
||||
const stubs = {
|
||||
GlFilteredSearchToken: {
|
||||
template: `<div><slot name="suggestions"></slot></div>`,
|
||||
},
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
config: {
|
||||
type: 'ref',
|
||||
icon: 'branch',
|
||||
title: 'Branch name',
|
||||
dataType: 'ref',
|
||||
unique: true,
|
||||
branches,
|
||||
projectId: '21',
|
||||
},
|
||||
value: {
|
||||
data: '',
|
||||
},
|
||||
};
|
||||
|
||||
const createComponent = (options, data) => {
|
||||
wrapper = shallowMount(PipelineBranchNameToken, {
|
||||
propsData: {
|
||||
...defaultProps,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
...data,
|
||||
};
|
||||
},
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
});
|
||||
|
||||
it('passes config correctly', () => {
|
||||
expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
|
||||
});
|
||||
|
||||
describe('displays loading icon correctly', () => {
|
||||
it('shows loading icon', () => {
|
||||
createComponent({ stubs }, { loading: true });
|
||||
|
||||
expect(findLoadingIcon().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not show loading icon', () => {
|
||||
createComponent({ stubs }, { loading: false });
|
||||
|
||||
expect(findLoadingIcon().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shows branches correctly', () => {
|
||||
it('renders all trigger authors', () => {
|
||||
createComponent({ stubs }, { branches, loading: false });
|
||||
|
||||
expect(findAllFilteredSearchSuggestions()).toHaveLength(branches.length);
|
||||
});
|
||||
|
||||
it('renders only the branch searched for', () => {
|
||||
const mockBranches = ['master'];
|
||||
createComponent({ stubs }, { branches: mockBranches, loading: false });
|
||||
|
||||
expect(findAllFilteredSearchSuggestions()).toHaveLength(mockBranches.length);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,4 +1,4 @@
|
|||
import { GlFilteredSearchToken, GlFilteredSearchSuggestion } from '@gitlab/ui';
|
||||
import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import PipelineTriggerAuthorToken from '~/pipelines/components/tokens/pipeline_trigger_author_token.vue';
|
||||
import { users } from '../mock_data';
|
||||
|
@ -8,6 +8,7 @@ describe('Pipeline Trigger Author Token', () => {
|
|||
|
||||
const findFilteredSearchToken = () => wrapper.find(GlFilteredSearchToken);
|
||||
const findAllFilteredSearchSuggestions = () => wrapper.findAll(GlFilteredSearchSuggestion);
|
||||
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
|
||||
|
||||
const stubs = {
|
||||
GlFilteredSearchToken: {
|
||||
|
@ -24,20 +25,27 @@ describe('Pipeline Trigger Author Token', () => {
|
|||
unique: true,
|
||||
triggerAuthors: users,
|
||||
},
|
||||
value: {
|
||||
data: '',
|
||||
},
|
||||
};
|
||||
|
||||
const createComponent = (props = {}, options) => {
|
||||
const createComponent = (options, data) => {
|
||||
wrapper = shallowMount(PipelineTriggerAuthorToken, {
|
||||
propsData: {
|
||||
...props,
|
||||
...defaultProps,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
...data,
|
||||
};
|
||||
},
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent({ value: { data: '' } });
|
||||
createComponent();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -49,14 +57,41 @@ describe('Pipeline Trigger Author Token', () => {
|
|||
expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
|
||||
});
|
||||
|
||||
describe('displays loading icon correctly', () => {
|
||||
it('shows loading icon', () => {
|
||||
createComponent({ stubs }, { loading: true });
|
||||
|
||||
expect(findLoadingIcon().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not show loading icon', () => {
|
||||
createComponent({ stubs }, { loading: false });
|
||||
|
||||
expect(findLoadingIcon().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shows trigger authors correctly', () => {
|
||||
beforeEach(() => {});
|
||||
|
||||
it('renders all trigger authors', () => {
|
||||
createComponent({ value: { data: '' } }, { stubs });
|
||||
expect(findAllFilteredSearchSuggestions()).toHaveLength(7);
|
||||
createComponent({ stubs }, { users, loading: false });
|
||||
|
||||
// should have length of all users plus the static 'Any' option
|
||||
expect(findAllFilteredSearchSuggestions()).toHaveLength(users.length + 1);
|
||||
});
|
||||
|
||||
it('renders only the trigger author searched for', () => {
|
||||
createComponent({ value: { data: 'root' } }, { stubs });
|
||||
createComponent(
|
||||
{ stubs },
|
||||
{
|
||||
users: [
|
||||
{ name: 'Arnold', username: 'admin', state: 'active', avatar_url: 'avatar-link' },
|
||||
],
|
||||
loading: false,
|
||||
},
|
||||
);
|
||||
|
||||
expect(findAllFilteredSearchSuggestions()).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -59,6 +59,32 @@ describe ClustersHelper do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#provider_icon' do
|
||||
it 'will return GCP logo with gcp argument' do
|
||||
logo = helper.provider_icon('gcp')
|
||||
|
||||
expect(logo).to match(%r(img alt="Google GKE" data-src="|/illustrations/logos/google_gke|svg))
|
||||
end
|
||||
|
||||
it 'will return AWS logo with aws argument' do
|
||||
logo = helper.provider_icon('aws')
|
||||
|
||||
expect(logo).to match(%r(img alt="Amazon EKS" data-src="|/illustrations/logos/amazon_eks|svg))
|
||||
end
|
||||
|
||||
it 'will return default logo with unknown provider' do
|
||||
logo = helper.provider_icon('unknown')
|
||||
|
||||
expect(logo).to match(%r(img alt="Kubernetes Cluster" data-src="|/illustrations/logos/kubernetes|svg))
|
||||
end
|
||||
|
||||
it 'will return default logo when provider is empty' do
|
||||
logo = helper.provider_icon
|
||||
|
||||
expect(logo).to match(%r(img alt="Kubernetes Cluster" data-src="|/illustrations/logos/kubernetes|svg))
|
||||
end
|
||||
end
|
||||
|
||||
describe '#cluster_type_label' do
|
||||
subject { helper.cluster_type_label(cluster_type) }
|
||||
|
||||
|
|
Loading…
Reference in a new issue