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-11-04 12:06:21 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2019-11-04 12:06:21 +0300
commit2b7a5214342baa2575b35868316ea9413d2afe1f (patch)
treef80a862f7fa382620b8f8a695d07b6d1734fc5f5
parent15a2d004be2f79160752d77f701c0f08e7f96973 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/docs.gitlab-ci.yml3
-rw-r--r--app/assets/javascripts/api.js20
-rw-r--r--app/assets/javascripts/clusters/clusters_bundle.js3
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue25
-rw-r--r--app/assets/javascripts/monitoring/components/embed.vue4
-rw-r--r--app/assets/javascripts/monitoring/stores/actions.js12
-rw-r--r--app/assets/javascripts/monitoring/stores/mutation_types.js1
-rw-r--r--app/assets/javascripts/monitoring/stores/mutations.js18
-rw-r--r--app/assets/javascripts/monitoring/stores/state.js4
-rw-r--r--app/assets/javascripts/monitoring/stores/utils.js6
-rw-r--r--app/assets/javascripts/project_select.js16
-rw-r--r--app/graphql/gitlab_schema.rb4
-rw-r--r--app/graphql/mutations/merge_requests/set_milestone.rb30
-rw-r--r--app/graphql/types/milestone_type.rb2
-rw-r--r--app/graphql/types/mutation_type.rb1
-rw-r--r--app/models/project_snippet.rb7
-rw-r--r--app/serializers/projects/serverless/service_entity.rb38
-rw-r--r--app/views/clusters/clusters/_advanced_settings.html.haml21
-rw-r--r--changelogs/unreleased/30695-remove-add-btn-in-approval-rule.yml5
-rw-r--r--changelogs/unreleased/31919-graphql-MR-sidebar-mutations.yml5
-rw-r--r--changelogs/unreleased/34372-serverless-function-description-does-not-show-up-for-newly-created-.yml5
-rw-r--r--changelogs/unreleased/34519-move-planels-in-dashboard-save-to-the-vuex-store.yml5
-rw-r--r--changelogs/unreleased/fe-cluster-management-project.yml5
-rw-r--r--changelogs/unreleased/remove-dind-for-ds.yml5
-rw-r--r--config/routes/project.rb1
-rw-r--r--doc/api/graphql/reference/index.md9
-rw-r--r--lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml66
-rw-r--r--lib/gitlab/database_importers/self_monitoring/project/create_service.rb30
-rw-r--r--lib/gitlab/etag_caching/router.rb4
-rw-r--r--lib/gitlab/prometheus/internal.rb45
-rw-r--r--locale/gitlab.pot9
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb3
-rw-r--r--spec/controllers/projects/serverless/functions_controller_spec.rb94
-rw-r--r--spec/frontend/api_spec.js20
-rw-r--r--spec/frontend/clusters/clusters_bundle_spec.js7
-rw-r--r--spec/frontend/fixtures/static/environments_logs.html3
-rw-r--r--spec/frontend/monitoring/embed/embed_spec.js4
-rw-r--r--spec/frontend/monitoring/embed/mock_data.js4
-rw-r--r--spec/graphql/mutations/merge_requests/set_milestone_spec.rb53
-rw-r--r--spec/javascripts/monitoring/charts/time_series_spec.js2
-rw-r--r--spec/javascripts/monitoring/components/dashboard_spec.js28
-rw-r--r--spec/javascripts/monitoring/store/actions_spec.js4
-rw-r--r--spec/javascripts/monitoring/store/mutations_spec.js34
-rw-r--r--spec/lib/gitlab/prometheus/internal_spec.rb108
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb66
-rw-r--r--spec/support/helpers/kubernetes_helpers.rb218
47 files changed, 855 insertions, 205 deletions
diff --git a/.gitlab/ci/docs.gitlab-ci.yml b/.gitlab/ci/docs.gitlab-ci.yml
index c93b503139f..00013d5d2ba 100644
--- a/.gitlab/ci/docs.gitlab-ci.yml
+++ b/.gitlab/ci/docs.gitlab-ci.yml
@@ -76,8 +76,7 @@ graphql-reference-verify:
- .default-only
- .default-before_script
- .only:changes-graphql
- variables:
- SETUP_DB: "false"
+ - .use-pg9
stage: test
needs: ["setup-test-env"]
script:
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 908dc730aa4..735cbb8e356 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -2,6 +2,8 @@ import $ from 'jquery';
import _ from 'underscore';
import axios from './lib/utils/axios_utils';
import { joinPaths } from './lib/utils/url_utility';
+import flash from '~/flash';
+import { __ } from '~/locale';
const Api = {
groupsPath: '/api/:version/groups.json',
@@ -29,6 +31,7 @@ const Api = {
usersPath: '/api/:version/users.json',
userPath: '/api/:version/users/:id',
userStatusPath: '/api/:version/users/:id/status',
+ userProjectsPath: '/api/:version/users/:id/projects',
userPostStatusPath: '/api/:version/user/status',
commitPath: '/api/:version/projects/:id/repository/commits',
applySuggestionPath: '/api/:version/suggestions/:id/apply',
@@ -239,7 +242,8 @@ const Api = {
.get(url, {
params: Object.assign({}, defaults, options),
})
- .then(({ data }) => callback(data));
+ .then(({ data }) => callback(data))
+ .catch(() => flash(__('Something went wrong while fetching projects')));
},
commitMultiple(id, data) {
@@ -348,6 +352,20 @@ const Api = {
});
},
+ userProjects(userId, query, options, callback) {
+ const url = Api.buildUrl(Api.userProjectsPath).replace(':id', userId);
+ const defaults = {
+ search: query,
+ per_page: 20,
+ };
+ return axios
+ .get(url, {
+ params: Object.assign({}, defaults, options),
+ })
+ .then(({ data }) => callback(data))
+ .catch(() => flash(__('Something went wrong while fetching projects')));
+ },
+
branches(id, query = '', options = {}) {
const url = Api.buildUrl(this.createBranchPath).replace(':id', encodeURIComponent(id));
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js
index 17251ccdffb..d471dcb1b06 100644
--- a/app/assets/javascripts/clusters/clusters_bundle.js
+++ b/app/assets/javascripts/clusters/clusters_bundle.js
@@ -13,6 +13,7 @@ import ClustersService from './services/clusters_service';
import ClustersStore from './stores/clusters_store';
import Applications from './components/applications.vue';
import setupToggleButtons from '../toggle_buttons';
+import initProjectSelectDropdown from '~/project_select';
const Environments = () => import('ee_component/clusters/components/environments.vue');
@@ -110,8 +111,10 @@ export default class Clusters {
this.ingressDomainHelpText &&
this.ingressDomainHelpText.querySelector('.js-ingress-domain-snippet');
+ initProjectSelectDropdown();
Clusters.initDismissableCallout();
initSettingsPanels();
+
const toggleButtonsContainer = document.querySelector('.js-cluster-enable-toggle-area');
if (toggleButtonsContainer) {
setupToggleButtons(toggleButtonsContainer);
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 725af920691..94c7bf1cee4 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -174,7 +174,7 @@ export default {
return this.customMetricsAvailable && this.customMetricsPath.length;
},
...mapState('monitoringDashboard', [
- 'groups',
+ 'dashboard',
'emptyState',
'showEmptyState',
'environments',
@@ -238,6 +238,7 @@ export default {
'setGettingStartedEmptyState',
'setEndpoints',
'setDashboardEnabled',
+ 'setPanelGroupMetrics',
]),
chartsWithData(charts) {
if (!this.useDashboardEndpoint) {
@@ -274,10 +275,17 @@ export default {
this.$toast.show(__('Link copied'));
},
// TODO: END
- removeGraph(metrics, graphIndex) {
- // At present graphs will not be removed, they should removed using the vuex store
- // See https://gitlab.com/gitlab-org/gitlab/issues/27835
- metrics.splice(graphIndex, 1);
+ updateMetrics(key, metrics) {
+ this.setPanelGroupMetrics({
+ metrics,
+ key,
+ });
+ },
+ removeMetric(key, metrics, graphIndex) {
+ this.setPanelGroupMetrics({
+ metrics: metrics.filter((v, i) => i !== graphIndex),
+ key,
+ });
},
showInvalidDateError() {
createFlash(s__('Metrics|Link contains an invalid time window.'));
@@ -447,7 +455,7 @@ export default {
<div v-if="!showEmptyState">
<graph-group
- v-for="(groupData, index) in groups"
+ v-for="(groupData, index) in dashboard.panel_groups"
:key="`${groupData.group}.${groupData.priority}`"
:name="groupData.group"
:show-panels="showPanels"
@@ -455,10 +463,11 @@ export default {
>
<template v-if="additionalPanelTypesEnabled">
<vue-draggable
- :list="groupData.metrics"
+ :value="groupData.metrics"
group="metrics-dashboard"
:component-data="{ attrs: { class: 'row mx-0 w-100' } }"
:disabled="!isRearrangingPanels"
+ @input="updateMetrics(groupData.key, $event)"
>
<div
v-for="(graphData, graphIndex) in groupData.metrics"
@@ -470,7 +479,7 @@ export default {
<div
v-if="isRearrangingPanels"
class="draggable-remove js-draggable-remove p-2 w-100 position-absolute d-flex justify-content-end"
- @click="removeGraph(groupData.metrics, graphIndex)"
+ @click="removeMetric(groupData.key, groupData.metrics, graphIndex)"
>
<a class="mx-2 p-2 draggable-remove-link" :aria-label="__('Remove')"
><icon name="close"
diff --git a/app/assets/javascripts/monitoring/components/embed.vue b/app/assets/javascripts/monitoring/components/embed.vue
index 7857aaa6ecc..80e9b7a9c57 100644
--- a/app/assets/javascripts/monitoring/components/embed.vue
+++ b/app/assets/javascripts/monitoring/components/embed.vue
@@ -35,9 +35,9 @@ export default {
};
},
computed: {
- ...mapState('monitoringDashboard', ['groups', 'metricsWithData']),
+ ...mapState('monitoringDashboard', ['dashboard', 'metricsWithData']),
charts() {
- const groupWithMetrics = this.groups.find(group =>
+ const groupWithMetrics = this.dashboard.panel_groups.find(group =>
group.metrics.find(chart => this.chartHasData(chart)),
) || { metrics: [] };
diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js
index 2cf34ddb45b..2f793a9e162 100644
--- a/app/assets/javascripts/monitoring/stores/actions.js
+++ b/app/assets/javascripts/monitoring/stores/actions.js
@@ -166,7 +166,7 @@ export const fetchPrometheusMetrics = ({ state, commit, dispatch }, params) => {
commit(types.REQUEST_METRICS_DATA);
const promises = [];
- state.groups.forEach(group => {
+ state.dashboard.panel_groups.forEach(group => {
group.panels.forEach(panel => {
panel.metrics.forEach(metric => {
promises.push(dispatch('fetchPrometheusMetric', { metric, params }));
@@ -221,5 +221,15 @@ export const fetchEnvironmentsData = ({ state, dispatch }) => {
});
};
+/**
+ * Set a new array of metrics to a panel group
+ * @param {*} data An object containing
+ * - `key` with a unique panel key
+ * - `metrics` with the metrics array
+ */
+export const setPanelGroupMetrics = ({ commit }, data) => {
+ commit(types.SET_PANEL_GROUP_METRICS, data);
+};
+
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
diff --git a/app/assets/javascripts/monitoring/stores/mutation_types.js b/app/assets/javascripts/monitoring/stores/mutation_types.js
index 9c546427c6e..4d05fa7beb9 100644
--- a/app/assets/javascripts/monitoring/stores/mutation_types.js
+++ b/app/assets/javascripts/monitoring/stores/mutation_types.js
@@ -16,3 +16,4 @@ export const SET_ENDPOINTS = 'SET_ENDPOINTS';
export const SET_GETTING_STARTED_EMPTY_STATE = 'SET_GETTING_STARTED_EMPTY_STATE';
export const SET_NO_DATA_EMPTY_STATE = 'SET_NO_DATA_EMPTY_STATE';
export const SET_SHOW_ERROR_BANNER = 'SET_SHOW_ERROR_BANNER';
+export const SET_PANEL_GROUP_METRICS = 'SET_PANEL_GROUP_METRICS';
diff --git a/app/assets/javascripts/monitoring/stores/mutations.js b/app/assets/javascripts/monitoring/stores/mutations.js
index 320b33d3d69..9e38314f8af 100644
--- a/app/assets/javascripts/monitoring/stores/mutations.js
+++ b/app/assets/javascripts/monitoring/stores/mutations.js
@@ -1,6 +1,7 @@
import Vue from 'vue';
+import { slugify } from '~/lib/utils/text_utility';
import * as types from './mutation_types';
-import { normalizeMetrics, sortMetrics, normalizeMetric, normalizeQueryResult } from './utils';
+import { normalizeMetrics, normalizeMetric, normalizeQueryResult } from './utils';
const normalizePanel = panel => panel.metrics.map(normalizeMetric);
@@ -10,10 +11,12 @@ export default {
state.showEmptyState = true;
},
[types.RECEIVE_METRICS_DATA_SUCCESS](state, groupData) {
- state.groups = groupData.map(group => {
+ state.dashboard.panel_groups = groupData.map((group, i) => {
+ const key = `${slugify(group.group || 'default')}-${i}`;
let { metrics = [], panels = [] } = group;
// each panel has metric information that needs to be normalized
+
panels = panels.map(panel => ({
...panel,
metrics: normalizePanel(panel),
@@ -32,11 +35,12 @@ export default {
return {
...group,
panels,
- metrics: normalizeMetrics(sortMetrics(metrics)),
+ key,
+ metrics: normalizeMetrics(metrics),
};
});
- if (!state.groups.length) {
+ if (!state.dashboard.panel_groups.length) {
state.emptyState = 'noData';
} else {
state.showEmptyState = false;
@@ -65,7 +69,7 @@ export default {
state.showEmptyState = false;
- state.groups.forEach(group => {
+ state.dashboard.panel_groups.forEach(group => {
group.metrics.forEach(metric => {
metric.queries.forEach(query => {
if (query.metric_id === metricId) {
@@ -105,4 +109,8 @@ export default {
[types.SET_SHOW_ERROR_BANNER](state, enabled) {
state.showErrorBanner = enabled;
},
+ [types.SET_PANEL_GROUP_METRICS](state, payload) {
+ const panelGroup = state.dashboard.panel_groups.find(pg => payload.key === pg.key);
+ panelGroup.metrics = payload.metrics;
+ },
};
diff --git a/app/assets/javascripts/monitoring/stores/state.js b/app/assets/javascripts/monitoring/stores/state.js
index e894e988f6a..5d7c46ca0c5 100644
--- a/app/assets/javascripts/monitoring/stores/state.js
+++ b/app/assets/javascripts/monitoring/stores/state.js
@@ -12,7 +12,9 @@ export default () => ({
emptyState: 'gettingStarted',
showEmptyState: true,
showErrorBanner: true,
- groups: [],
+ dashboard: {
+ panel_groups: [],
+ },
deploymentData: [],
environments: [],
metricsWithData: [],
diff --git a/app/assets/javascripts/monitoring/stores/utils.js b/app/assets/javascripts/monitoring/stores/utils.js
index a19829f0c65..8a396b15a31 100644
--- a/app/assets/javascripts/monitoring/stores/utils.js
+++ b/app/assets/javascripts/monitoring/stores/utils.js
@@ -82,12 +82,6 @@ export const normalizeMetric = (metric = {}) =>
'id',
);
-export const sortMetrics = metrics =>
- _.chain(metrics)
- .sortBy('title')
- .sortBy('weight')
- .value();
-
export const normalizeQueryResult = timeSeries => {
let normalizedResult = {};
diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js
index 0fbb7e5ca42..81f2fc2e686 100644
--- a/app/assets/javascripts/project_select.js
+++ b/app/assets/javascripts/project_select.js
@@ -9,7 +9,9 @@ const projectSelect = () => {
$('.ajax-project-select').each(function(i, select) {
var placeholder;
const simpleFilter = $(select).data('simpleFilter') || false;
+ const isInstantiated = $(select).data('select2');
this.groupId = $(select).data('groupId');
+ this.userId = $(select).data('userId');
this.includeGroups = $(select).data('includeGroups');
this.allProjects = $(select).data('allProjects') || false;
this.orderBy = $(select).data('orderBy') || 'id';
@@ -63,6 +65,18 @@ const projectSelect = () => {
},
projectsCallback,
);
+ } else if (_this.userId) {
+ return Api.userProjects(
+ _this.userId,
+ query.term,
+ {
+ with_issues_enabled: _this.withIssuesEnabled,
+ with_merge_requests_enabled: _this.withMergeRequestsEnabled,
+ with_shared: _this.withShared,
+ include_subgroups: _this.includeProjectsInSubgroups,
+ },
+ projectsCallback,
+ );
} else {
return Api.projects(
query.term,
@@ -96,7 +110,7 @@ const projectSelect = () => {
dropdownCssClass: 'ajax-project-dropdown',
});
- if (simpleFilter) return select;
+ if (isInstantiated || simpleFilter) return select;
return new ProjectSelectComboButton(select);
});
};
diff --git a/app/graphql/gitlab_schema.rb b/app/graphql/gitlab_schema.rb
index 1899278ff3c..a5ddf316572 100644
--- a/app/graphql/gitlab_schema.rb
+++ b/app/graphql/gitlab_schema.rb
@@ -46,7 +46,7 @@ class GitlabSchema < GraphQL::Schema
super(query_str, **kwargs)
end
- def id_from_object(object)
+ def id_from_object(object, _type = nil, _ctx = nil)
unless object.respond_to?(:to_global_id)
# This is an error in our schema and needs to be solved. So raise a
# more meaningful error message
@@ -57,7 +57,7 @@ class GitlabSchema < GraphQL::Schema
object.to_global_id
end
- def object_from_id(global_id)
+ def object_from_id(global_id, _ctx = nil)
gid = GlobalID.parse(global_id)
unless gid
diff --git a/app/graphql/mutations/merge_requests/set_milestone.rb b/app/graphql/mutations/merge_requests/set_milestone.rb
new file mode 100644
index 00000000000..707d6677952
--- /dev/null
+++ b/app/graphql/mutations/merge_requests/set_milestone.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Mutations
+ module MergeRequests
+ class SetMilestone < Base
+ graphql_name 'MergeRequestSetMilestone'
+
+ argument :milestone_id,
+ GraphQL::ID_TYPE,
+ required: false,
+ loads: Types::MilestoneType,
+ description: <<~DESC
+ The milestone to assign to the merge request.
+ DESC
+
+ def resolve(project_path:, iid:, milestone: nil)
+ merge_request = authorized_find!(project_path: project_path, iid: iid)
+ project = merge_request.project
+
+ ::MergeRequests::UpdateService.new(project, current_user, milestone: milestone)
+ .execute(merge_request)
+
+ {
+ merge_request: merge_request,
+ errors: merge_request.errors.full_messages
+ }
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/milestone_type.rb b/app/graphql/types/milestone_type.rb
index 1d3a1231bca..9c3afb28674 100644
--- a/app/graphql/types/milestone_type.rb
+++ b/app/graphql/types/milestone_type.rb
@@ -6,6 +6,8 @@ module Types
authorize :read_milestone
+ field :id, GraphQL::ID_TYPE, null: false,
+ description: 'ID of the milestone'
field :description, GraphQL::STRING_TYPE, null: true,
description: 'Description of the milestone'
field :title, GraphQL::STRING_TYPE, null: false,
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 17f922a5e54..c636bf0e31f 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -9,6 +9,7 @@ module Types
mount_mutation Mutations::AwardEmojis::Add
mount_mutation Mutations::AwardEmojis::Remove
mount_mutation Mutations::AwardEmojis::Toggle
+ mount_mutation Mutations::MergeRequests::SetMilestone
mount_mutation Mutations::MergeRequests::SetWip, calls_gitaly: true
mount_mutation Mutations::Notes::Create::Note, calls_gitaly: true
mount_mutation Mutations::Notes::Create::DiffNote, calls_gitaly: true
diff --git a/app/models/project_snippet.rb b/app/models/project_snippet.rb
index b3585c4cf4c..e732c1bd86f 100644
--- a/app/models/project_snippet.rb
+++ b/app/models/project_snippet.rb
@@ -2,13 +2,6 @@
class ProjectSnippet < Snippet
belongs_to :project
- belongs_to :author, class_name: "User"
validates :project, presence: true
-
- # Scopes
- scope :fresh, -> { order("created_at DESC") }
-
- participant :author
- participant :notes_with_associations
end
diff --git a/app/serializers/projects/serverless/service_entity.rb b/app/serializers/projects/serverless/service_entity.rb
index a1e0bf02d11..10360e575bb 100644
--- a/app/serializers/projects/serverless/service_entity.rb
+++ b/app/serializers/projects/serverless/service_entity.rb
@@ -44,28 +44,52 @@ module Projects
end
expose :url do |service|
- service.dig('status', 'url') || "http://#{service.dig('status', 'domain')}"
+ knative_06_07_url(service) || knative_05_url(service)
end
expose :description do |service|
+ knative_07_description(service) || knative_05_06_description(service)
+ end
+
+ expose :image do |service|
service.dig(
'spec',
'runLatest',
'configuration',
- 'revisionTemplate',
+ 'build',
+ 'template',
+ 'name')
+ end
+
+ private
+
+ def knative_07_description(service)
+ service.dig(
+ 'spec',
+ 'template',
'metadata',
'annotations',
- 'Description')
+ 'Description'
+ )
end
- expose :image do |service|
+ def knative_05_url(service)
+ "http://#{service.dig('status', 'domain')}"
+ end
+
+ def knative_06_07_url(service)
+ service.dig('status', 'url')
+ end
+
+ def knative_05_06_description(service)
service.dig(
'spec',
'runLatest',
'configuration',
- 'build',
- 'template',
- 'name')
+ 'revisionTemplate',
+ 'metadata',
+ 'annotations',
+ 'Description')
end
end
end
diff --git a/app/views/clusters/clusters/_advanced_settings.html.haml b/app/views/clusters/clusters/_advanced_settings.html.haml
index 8005dcbf65f..493d7a00854 100644
--- a/app/views/clusters/clusters/_advanced_settings.html.haml
+++ b/app/views/clusters/clusters/_advanced_settings.html.haml
@@ -1,3 +1,9 @@
+- group_id = @cluster.group.id if @cluster.group_type?
+
+- if @cluster.project_type?
+ - group_id = @cluster.project.group.id if @cluster.project.group
+ - user_id = @cluster.project.namespace.owner_id unless group_id
+
- if can?(current_user, :admin_cluster, @cluster)
- unless @cluster.provided_by_user?
.append-bottom-20
@@ -7,6 +13,21 @@
- link_gke = link_to(s_('ClusterIntegration|Google Kubernetes Engine'), @cluster.gke_cluster_url, target: '_blank', rel: 'noopener noreferrer')
= s_('ClusterIntegration|Manage your Kubernetes cluster by visiting %{link_gke}').html_safe % { link_gke: link_gke }
+ = form_for @cluster, url: clusterable.cluster_path(@cluster), as: :cluster, html: { class: 'cluster_management_form' } do |field|
+
+ %h5
+ = s_('ClusterIntegration|Cluster management project (alpha)')
+
+ .form-group
+ .form-text.text-muted
+ = project_select_tag('cluster[management_project_id]', class: 'hidden-filter-value', toggle_class: 'js-project-search js-project-filter js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-project js-filter-submit',
+ placeholder: _('Select project'), idAttribute: 'id', data: { order_by: 'last_activity_at', idattribute: 'id', simple_filter: true, allow_clear: true, include_groups: false, include_projects_in_subgroups: true, group_id: group_id, user_id: user_id }, value: @cluster.management_project_id)
+ .text-muted
+ = s_('ClusterIntegration|A cluster management project can be used to run deployment jobs with Kubernetes <code>cluster-admin</code> privileges.').html_safe
+ = link_to _('More information'), help_page_path('user/clusters/management_project.md'), target: '_blank'
+ .form-group
+ = field.submit _('Save changes'), class: 'btn btn-success qa-save-domain'
+
.sub-section.form-group
%h4.text-danger
= s_('ClusterIntegration|Remove Kubernetes cluster integration')
diff --git a/changelogs/unreleased/30695-remove-add-btn-in-approval-rule.yml b/changelogs/unreleased/30695-remove-add-btn-in-approval-rule.yml
new file mode 100644
index 00000000000..5ef0c9ef67a
--- /dev/null
+++ b/changelogs/unreleased/30695-remove-add-btn-in-approval-rule.yml
@@ -0,0 +1,5 @@
+---
+title: Can directly add approvers to approval rule
+merge_request: 18965
+author:
+type: changed
diff --git a/changelogs/unreleased/31919-graphql-MR-sidebar-mutations.yml b/changelogs/unreleased/31919-graphql-MR-sidebar-mutations.yml
new file mode 100644
index 00000000000..e8d47abd169
--- /dev/null
+++ b/changelogs/unreleased/31919-graphql-MR-sidebar-mutations.yml
@@ -0,0 +1,5 @@
+---
+title: 'GraphQL: Add Merge Request milestone mutation'
+merge_request: 19257
+author:
+type: added
diff --git a/changelogs/unreleased/34372-serverless-function-description-does-not-show-up-for-newly-created-.yml b/changelogs/unreleased/34372-serverless-function-description-does-not-show-up-for-newly-created-.yml
new file mode 100644
index 00000000000..0a7bfd5fb4f
--- /dev/null
+++ b/changelogs/unreleased/34372-serverless-function-description-does-not-show-up-for-newly-created-.yml
@@ -0,0 +1,5 @@
+---
+title: Fix serverless function descriptions not showing on Knative 0.7
+merge_request: 18973
+author:
+type: fixed
diff --git a/changelogs/unreleased/34519-move-planels-in-dashboard-save-to-the-vuex-store.yml b/changelogs/unreleased/34519-move-planels-in-dashboard-save-to-the-vuex-store.yml
new file mode 100644
index 00000000000..669a0c8bd93
--- /dev/null
+++ b/changelogs/unreleased/34519-move-planels-in-dashboard-save-to-the-vuex-store.yml
@@ -0,0 +1,5 @@
+---
+title: Save dashboard changes by the user into the vuex store
+merge_request: 18862
+author:
+type: changed
diff --git a/changelogs/unreleased/fe-cluster-management-project.yml b/changelogs/unreleased/fe-cluster-management-project.yml
new file mode 100644
index 00000000000..43b4ddc8724
--- /dev/null
+++ b/changelogs/unreleased/fe-cluster-management-project.yml
@@ -0,0 +1,5 @@
+---
+title: Add ability to select a Cluster management project
+merge_request: 18928
+author:
+type: added
diff --git a/changelogs/unreleased/remove-dind-for-ds.yml b/changelogs/unreleased/remove-dind-for-ds.yml
new file mode 100644
index 00000000000..b60c983d91e
--- /dev/null
+++ b/changelogs/unreleased/remove-dind-for-ds.yml
@@ -0,0 +1,5 @@
+---
+title: Dependency Scanning template that doesn't rely on Docker-in-Docker
+merge_request:
+author:
+type: other
diff --git a/config/routes/project.rb b/config/routes/project.rb
index 24b4f310350..d628e1ea650 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -433,6 +433,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
Gitlab.ee do
get :logs
+ get '/pods/(:pod_name)/containers/(:container_name)/logs', to: 'environments#k8s_pod_logs', as: :k8s_pod_logs
end
end
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 1b663acd5fb..bfda8ff1194 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -473,6 +473,14 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `cherryPickOnCurrentMergeRequest` | Boolean! | Whether or not a user can perform `cherry_pick_on_current_merge_request` on this resource |
| `revertOnCurrentMergeRequest` | Boolean! | Whether or not a user can perform `revert_on_current_merge_request` on this resource |
+### MergeRequestSetMilestonePayload
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Reasons why the mutation failed. |
+| `mergeRequest` | MergeRequest | The merge request after mutation |
+
### MergeRequestSetWipPayload
| Name | Type | Description |
@@ -492,6 +500,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
+| `id` | ID! | ID of the milestone |
| `description` | String | Description of the milestone |
| `title` | String! | Title of the milestone |
| `state` | String! | State of the milestone |
diff --git a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
index c8930bc6263..53ba9792bd0 100644
--- a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
@@ -4,6 +4,12 @@
# List of the variables: https://gitlab.com/gitlab-org/security-products/dependency-scanning#settings
# How to set: https://docs.gitlab.com/ee/ci/yaml/#variables
+variables:
+ DS_ANALYZER_IMAGE_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
+ DS_DEFAULT_ANALYZERS: "gemnasium, retire.js, gemnasium-python, gemnasium-maven, bundler-audit"
+ DS_MAJOR_VERSION: 2
+ DS_DISABLE_DIND: "false"
+
dependency_scanning:
stage: test
image: docker:stable
@@ -61,3 +67,63 @@ dependency_scanning:
except:
variables:
- $DEPENDENCY_SCANNING_DISABLED
+ - $DS_DISABLE_DIND == 'true'
+
+.analyzer:
+ extends: dependency_scanning
+ services: []
+ except:
+ variables:
+ - $DS_DISABLE_DIND == 'false'
+ script:
+ - /analyzer run
+
+gemnasium-dependency_scanning:
+ extends: .analyzer
+ image:
+ name: "$DS_ANALYZER_IMAGE_PREFIX/gemnasium:$DS_MAJOR_VERSION"
+ only:
+ variables:
+ - $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $DS_DEFAULT_ANALYZERS =~ /gemnasium/ &&
+ $CI_PROJECT_REPOSITORY_LANGUAGES =~ /ruby|javascript|php/
+
+gemnasium-maven-dependency_scanning:
+ extends: .analyzer
+ image:
+ name: "$DS_ANALYZER_IMAGE_PREFIX/gemnasium-maven:$DS_MAJOR_VERSION"
+ only:
+ variables:
+ - $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $DS_DEFAULT_ANALYZERS =~ /gemnasium-maven/ &&
+ $CI_PROJECT_REPOSITORY_LANGUAGES =~ /\bjava\b/
+
+gemnasium-python-dependency_scanning:
+ extends: .analyzer
+ image:
+ name: "$DS_ANALYZER_IMAGE_PREFIX/gemnasium-python:$DS_MAJOR_VERSION"
+ only:
+ variables:
+ - $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $DS_DEFAULT_ANALYZERS =~ /gemnasium-python/ &&
+ $CI_PROJECT_REPOSITORY_LANGUAGES =~ /python/
+
+bundler-audit-dependency_scanning:
+ extends: .analyzer
+ image:
+ name: "$DS_ANALYZER_IMAGE_PREFIX/bundler-audit:$DS_MAJOR_VERSION"
+ only:
+ variables:
+ - $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $DS_DEFAULT_ANALYZERS =~ /bundler-audit/ &&
+ $CI_PROJECT_REPOSITORY_LANGUAGES =~ /ruby/
+
+retire-js-dependency_scanning:
+ extends: .analyzer
+ image:
+ name: "$DS_ANALYZER_IMAGE_PREFIX/retire.js:$DS_MAJOR_VERSION"
+ only:
+ variables:
+ - $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $DS_DEFAULT_ANALYZERS =~ /retire.js/ &&
+ $CI_PROJECT_REPOSITORY_LANGUAGES =~ /javascript/
diff --git a/lib/gitlab/database_importers/self_monitoring/project/create_service.rb b/lib/gitlab/database_importers/self_monitoring/project/create_service.rb
index dfef158cc1d..4677e984305 100644
--- a/lib/gitlab/database_importers/self_monitoring/project/create_service.rb
+++ b/lib/gitlab/database_importers/self_monitoring/project/create_service.rb
@@ -176,19 +176,11 @@ module Gitlab
end
def prometheus_enabled?
- Gitlab.config.prometheus.enable if Gitlab.config.prometheus
- rescue Settingslogic::MissingSetting
- log_error('prometheus.enable is not present in config/gitlab.yml')
-
- false
+ ::Gitlab::Prometheus::Internal.prometheus_enabled?
end
def prometheus_listen_address
- Gitlab.config.prometheus.listen_address.to_s if Gitlab.config.prometheus
- rescue Settingslogic::MissingSetting
- log_error('Prometheus listen_address is not present in config/gitlab.yml')
-
- nil
+ ::Gitlab::Prometheus::Internal.listen_address
end
def instance_admins
@@ -231,23 +223,7 @@ module Gitlab
end
def internal_prometheus_listen_address_uri
- if prometheus_listen_address.starts_with?('0.0.0.0:')
- # 0.0.0.0:9090
- port = ':' + prometheus_listen_address.split(':').second
- 'http://localhost' + port
-
- elsif prometheus_listen_address.starts_with?(':')
- # :9090
- 'http://localhost' + prometheus_listen_address
-
- elsif prometheus_listen_address.starts_with?('http')
- # https://localhost:9090
- prometheus_listen_address
-
- else
- # localhost:9090
- 'http://' + prometheus_listen_address
- end
+ ::Gitlab::Prometheus::Internal.uri
end
def prometheus_service_attributes
diff --git a/lib/gitlab/etag_caching/router.rb b/lib/gitlab/etag_caching/router.rb
index 3d14a8dde8d..efddda0ec65 100644
--- a/lib/gitlab/etag_caching/router.rb
+++ b/lib/gitlab/etag_caching/router.rb
@@ -3,8 +3,6 @@
module Gitlab
module EtagCaching
class Router
- prepend_if_ee('EE::Gitlab::EtagCaching::Router') # rubocop: disable Cop/InjectEnterpriseEditionModule
-
Route = Struct.new(:regexp, :name)
# We enable an ETag for every request matching the regex.
# To match a regex the path needs to match the following:
@@ -80,3 +78,5 @@ module Gitlab
end
end
end
+
+Gitlab::EtagCaching::Router.prepend_if_ee('EE::Gitlab::EtagCaching::Router')
diff --git a/lib/gitlab/prometheus/internal.rb b/lib/gitlab/prometheus/internal.rb
new file mode 100644
index 00000000000..d59352119ba
--- /dev/null
+++ b/lib/gitlab/prometheus/internal.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Prometheus
+ class Internal
+ def self.uri
+ return if listen_address.blank?
+
+ if listen_address.starts_with?('0.0.0.0:')
+ # 0.0.0.0:9090
+ port = ':' + listen_address.split(':').second
+ 'http://localhost' + port
+
+ elsif listen_address.starts_with?(':')
+ # :9090
+ 'http://localhost' + listen_address
+
+ elsif listen_address.starts_with?('http')
+ # https://localhost:9090
+ listen_address
+
+ else
+ # localhost:9090
+ 'http://' + listen_address
+ end
+ end
+
+ def self.listen_address
+ Gitlab.config.prometheus.listen_address.to_s if Gitlab.config.prometheus
+ rescue Settingslogic::MissingSetting
+ Gitlab::AppLogger.error('Prometheus listen_address is not present in config/gitlab.yml')
+
+ nil
+ end
+
+ def self.prometheus_enabled?
+ Gitlab.config.prometheus.enable if Gitlab.config.prometheus
+ rescue Settingslogic::MissingSetting
+ Gitlab::AppLogger.error('prometheus.enable is not present in config/gitlab.yml')
+
+ false
+ end
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 93cbf73979e..f95f329442c 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -3399,6 +3399,9 @@ msgstr ""
msgid "ClusterIntegration|%{title} updated successfully."
msgstr ""
+msgid "ClusterIntegration|A cluster management project can be used to run deployment jobs with Kubernetes <code>cluster-admin</code> privileges."
+msgstr ""
+
msgid "ClusterIntegration|A service token scoped to %{code}kube-system%{end_code} with %{code}cluster-admin%{end_code} privileges."
msgstr ""
@@ -3507,6 +3510,9 @@ msgstr ""
msgid "ClusterIntegration|Cluster health"
msgstr ""
+msgid "ClusterIntegration|Cluster management project (alpha)"
+msgstr ""
+
msgid "ClusterIntegration|Cluster name is required."
msgstr ""
@@ -15587,6 +15593,9 @@ msgstr ""
msgid "Something went wrong while fetching latest comments."
msgstr ""
+msgid "Something went wrong while fetching projects"
+msgstr ""
+
msgid "Something went wrong while fetching related merge requests."
msgstr ""
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb
index e42d538fdf8..a0fe957f97e 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ # Failure issue: https://gitlab.com/gitlab-org/gitlab/issues/34551
+ context 'Create', :quarantine do
describe 'File templates' do
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
index 0a89f0c9d41..957674353d6 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
module QA
- context 'Create' do
+ # Failure issue: https://gitlab.com/gitlab-org/gitlab/issues/34551
+ context 'Create', :quarantine do
describe 'Web IDE file templates' do
include Runtime::Fixtures
diff --git a/spec/controllers/projects/serverless/functions_controller_spec.rb b/spec/controllers/projects/serverless/functions_controller_spec.rb
index eccc8e1d5de..73fb0fad646 100644
--- a/spec/controllers/projects/serverless/functions_controller_spec.rb
+++ b/spec/controllers/projects/serverless/functions_controller_spec.rb
@@ -13,6 +13,10 @@ describe Projects::Serverless::FunctionsController do
let(:environment) { create(:environment, project: project) }
let!(:deployment) { create(:deployment, :success, environment: environment, cluster: cluster) }
let(:knative_services_finder) { environment.knative_services_finder }
+ let(:function_description) { 'A serverless function' }
+ let(:knative_stub_options) do
+ { namespace: namespace.namespace, name: cluster.project.name, description: function_description }
+ end
let(:namespace) do
create(:cluster_kubernetes_namespace,
@@ -114,40 +118,33 @@ describe Projects::Serverless::FunctionsController do
expect(response).to have_gitlab_http_status(200)
expect(json_response).to include(
- "name" => project.name,
- "url" => "http://#{project.name}.#{namespace.namespace}.example.com",
- "podcount" => 1
+ 'name' => project.name,
+ 'url' => "http://#{project.name}.#{namespace.namespace}.example.com",
+ 'description' => function_description,
+ 'podcount' => 1
)
end
end
- context 'on Knative 0.5' do
+ context 'on Knative 0.5.0' do
+ before do
+ prepare_knative_stubs(knative_05_service(knative_stub_options))
+ end
+
+ include_examples 'GET #show with valid data'
+ end
+
+ context 'on Knative 0.6.0' do
before do
- stub_kubeclient_service_pods
- stub_reactive_cache(knative_services_finder,
- {
- services: kube_knative_services_body(
- legacy_knative: true,
- namespace: namespace.namespace,
- name: cluster.project.name
- )["items"],
- pods: kube_knative_pods_body(cluster.project.name, namespace.namespace)["items"]
- },
- *knative_services_finder.cache_args)
+ prepare_knative_stubs(knative_06_service(knative_stub_options))
end
include_examples 'GET #show with valid data'
end
- context 'on Knative 0.6 or 0.7' do
+ context 'on Knative 0.7.0' do
before do
- stub_kubeclient_service_pods
- stub_reactive_cache(knative_services_finder,
- {
- services: kube_knative_services_body(namespace: namespace.namespace, name: cluster.project.name)["items"],
- pods: kube_knative_pods_body(cluster.project.name, namespace.namespace)["items"]
- },
- *knative_services_finder.cache_args)
+ prepare_knative_stubs(knative_07_service(knative_stub_options))
end
include_examples 'GET #show with valid data'
@@ -172,11 +169,12 @@ describe Projects::Serverless::FunctionsController do
expect(response).to have_gitlab_http_status(200)
expect(json_response).to match({
- "knative_installed" => "checking",
- "functions" => [
+ 'knative_installed' => 'checking',
+ 'functions' => [
a_hash_including(
- "name" => project.name,
- "url" => "http://#{project.name}.#{namespace.namespace}.example.com"
+ 'name' => project.name,
+ 'url' => "http://#{project.name}.#{namespace.namespace}.example.com",
+ 'description' => function_description
)
]
})
@@ -189,36 +187,38 @@ describe Projects::Serverless::FunctionsController do
end
end
- context 'on Knative 0.5' do
+ context 'on Knative 0.5.0' do
before do
- stub_kubeclient_service_pods
- stub_reactive_cache(knative_services_finder,
- {
- services: kube_knative_services_body(
- legacy_knative: true,
- namespace: namespace.namespace,
- name: cluster.project.name
- )["items"],
- pods: kube_knative_pods_body(cluster.project.name, namespace.namespace)["items"]
- },
- *knative_services_finder.cache_args)
+ prepare_knative_stubs(knative_05_service(knative_stub_options))
end
include_examples 'GET #index with data'
end
- context 'on Knative 0.6 or 0.7' do
+ context 'on Knative 0.6.0' do
before do
- stub_kubeclient_service_pods
- stub_reactive_cache(knative_services_finder,
- {
- services: kube_knative_services_body(namespace: namespace.namespace, name: cluster.project.name)["items"],
- pods: kube_knative_pods_body(cluster.project.name, namespace.namespace)["items"]
- },
- *knative_services_finder.cache_args)
+ prepare_knative_stubs(knative_06_service(knative_stub_options))
end
include_examples 'GET #index with data'
end
+
+ context 'on Knative 0.7.0' do
+ before do
+ prepare_knative_stubs(knative_07_service(knative_stub_options))
+ end
+
+ include_examples 'GET #index with data'
+ end
+ end
+
+ def prepare_knative_stubs(knative_service)
+ stub_kubeclient_service_pods
+ stub_reactive_cache(knative_services_finder,
+ {
+ services: [knative_service],
+ pods: kube_knative_pods_body(cluster.project.name, namespace.namespace)["items"]
+ },
+ *knative_services_finder.cache_args)
end
end
diff --git a/spec/frontend/api_spec.js b/spec/frontend/api_spec.js
index 62ba0d36982..cef50bf553c 100644
--- a/spec/frontend/api_spec.js
+++ b/spec/frontend/api_spec.js
@@ -467,6 +467,26 @@ describe('Api', () => {
});
});
+ describe('user projects', () => {
+ it('fetches all projects that belong to a particular user', done => {
+ const query = 'dummy query';
+ const options = { unused: 'option' };
+ const userId = '123456';
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/users/${userId}/projects`;
+ mock.onGet(expectedUrl).reply(200, [
+ {
+ name: 'test',
+ },
+ ]);
+
+ Api.userProjects(userId, query, options, response => {
+ expect(response.length).toBe(1);
+ expect(response[0].name).toBe('test');
+ done();
+ });
+ });
+ });
+
describe('commitPipelines', () => {
it('fetches pipelines for a given commit', done => {
const projectId = 'example/foobar';
diff --git a/spec/frontend/clusters/clusters_bundle_spec.js b/spec/frontend/clusters/clusters_bundle_spec.js
index 517d8781600..317d3f3012b 100644
--- a/spec/frontend/clusters/clusters_bundle_spec.js
+++ b/spec/frontend/clusters/clusters_bundle_spec.js
@@ -10,8 +10,10 @@ import axios from '~/lib/utils/axios_utils';
import { loadHTMLFixture } from 'helpers/fixtures';
import { setTestTimeout } from 'helpers/timeout';
import $ from 'jquery';
+import initProjectSelectDropdown from '~/project_select';
jest.mock('~/lib/utils/poll');
+jest.mock('~/project_select');
const { INSTALLING, INSTALLABLE, INSTALLED, UNINSTALLING } = APPLICATION_STATUS;
@@ -44,6 +46,7 @@ describe('Clusters', () => {
afterEach(() => {
cluster.destroy();
mock.restore();
+ jest.clearAllMocks();
});
describe('class constructor', () => {
@@ -55,6 +58,10 @@ describe('Clusters', () => {
it('should call initPolling on construct', () => {
expect(cluster.initPolling).toHaveBeenCalled();
});
+
+ it('should call initProjectSelectDropdown on construct', () => {
+ expect(initProjectSelectDropdown).toHaveBeenCalled();
+ });
});
describe('toggle', () => {
diff --git a/spec/frontend/fixtures/static/environments_logs.html b/spec/frontend/fixtures/static/environments_logs.html
index 4e242b77d1f..88bb0a3ed41 100644
--- a/spec/frontend/fixtures/static/environments_logs.html
+++ b/spec/frontend/fixtures/static/environments_logs.html
@@ -2,7 +2,8 @@
class="js-kubernetes-logs"
data-current-environment-name="production"
data-environments-path="/root/my-project/environments.json"
- data-logs-endpoint="/root/my-project/environments/1/logs.json"
+ data-project-full-path="root/my-project"
+ data-environment-id=1
>
<div class="build-page-pod-logs">
<div class="build-trace-container prepend-top-default">
diff --git a/spec/frontend/monitoring/embed/embed_spec.js b/spec/frontend/monitoring/embed/embed_spec.js
index 5de1a7c4c3b..3e22b0858e6 100644
--- a/spec/frontend/monitoring/embed/embed_spec.js
+++ b/spec/frontend/monitoring/embed/embed_spec.js
@@ -61,8 +61,8 @@ describe('Embed', () => {
describe('metrics are available', () => {
beforeEach(() => {
- store.state.monitoringDashboard.groups = groups;
- store.state.monitoringDashboard.groups[0].metrics = metricsData;
+ store.state.monitoringDashboard.dashboard.panel_groups = groups;
+ store.state.monitoringDashboard.dashboard.panel_groups[0].metrics = metricsData;
store.state.monitoringDashboard.metricsWithData = metricsWithData;
mountComponent();
diff --git a/spec/frontend/monitoring/embed/mock_data.js b/spec/frontend/monitoring/embed/mock_data.js
index df4acb82e95..1685021fd4b 100644
--- a/spec/frontend/monitoring/embed/mock_data.js
+++ b/spec/frontend/monitoring/embed/mock_data.js
@@ -81,7 +81,9 @@ export const metricsData = [
export const initialState = {
monitoringDashboard: {},
- groups: [],
+ dashboard: {
+ panel_groups: [],
+ },
metricsWithData: [],
useDashboardEndpoint: true,
};
diff --git a/spec/graphql/mutations/merge_requests/set_milestone_spec.rb b/spec/graphql/mutations/merge_requests/set_milestone_spec.rb
new file mode 100644
index 00000000000..c2792a4bc25
--- /dev/null
+++ b/spec/graphql/mutations/merge_requests/set_milestone_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Mutations::MergeRequests::SetMilestone do
+ let(:merge_request) { create(:merge_request) }
+ let(:user) { create(:user) }
+ subject(:mutation) { described_class.new(object: nil, context: { current_user: user }) }
+
+ describe '#resolve' do
+ let(:milestone) { create(:milestone, project: merge_request.project) }
+ let(:mutated_merge_request) { subject[:merge_request] }
+ subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, milestone: milestone) }
+
+ it 'raises an error if the resource is not accessible to the user' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+
+ context 'when the user can update the merge request' do
+ before do
+ merge_request.project.add_developer(user)
+ end
+
+ it 'returns the merge request with the milestone' do
+ expect(mutated_merge_request).to eq(merge_request)
+ expect(mutated_merge_request.milestone).to eq(milestone)
+ expect(subject[:errors]).to be_empty
+ end
+
+ it 'returns errors merge request could not be updated' do
+ # Make the merge request invalid
+ merge_request.allow_broken = true
+ merge_request.update!(source_project: nil)
+
+ expect(subject[:errors]).not_to be_empty
+ end
+
+ context 'when passing milestone_id as nil' do
+ let(:milestone) { nil }
+
+ it 'removes the milestone' do
+ merge_request.update!(milestone: create(:milestone, project: merge_request.project))
+
+ expect(mutated_merge_request.milestone).to eq(nil)
+ end
+
+ it 'does not do anything if the MR already does not have a milestone' do
+ expect(mutated_merge_request.milestone).to eq(nil)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/javascripts/monitoring/charts/time_series_spec.js b/spec/javascripts/monitoring/charts/time_series_spec.js
index 31ea9ede9de..42feaca616b 100644
--- a/spec/javascripts/monitoring/charts/time_series_spec.js
+++ b/spec/javascripts/monitoring/charts/time_series_spec.js
@@ -23,7 +23,7 @@ describe('Time series component', () => {
store = createStore();
store.commit(`monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, MonitoringMock.data);
store.commit(`monitoringDashboard/${types.RECEIVE_DEPLOYMENTS_DATA_SUCCESS}`, deploymentData);
- [mockGraphData] = store.state.monitoringDashboard.groups[0].metrics;
+ [, mockGraphData] = store.state.monitoringDashboard.dashboard.panel_groups[0].metrics;
makeTimeSeriesChart = (graphData, type) =>
shallowMount(TimeSeries, {
diff --git a/spec/javascripts/monitoring/components/dashboard_spec.js b/spec/javascripts/monitoring/components/dashboard_spec.js
index be7ab24185d..4070de4cc35 100644
--- a/spec/javascripts/monitoring/components/dashboard_spec.js
+++ b/spec/javascripts/monitoring/components/dashboard_spec.js
@@ -442,6 +442,28 @@ describe('Dashboard', () => {
expect(findEnabledDraggables()).toEqual(findDraggables());
});
+ it('metrics can be swapped', done => {
+ const firstDraggable = findDraggables().at(0);
+ const mockMetrics = [...metricsGroupsAPIResponse.data[0].metrics];
+ const value = () => firstDraggable.props('value');
+
+ expect(value().length).toBe(mockMetrics.length);
+ value().forEach((metric, i) => {
+ expect(metric.title).toBe(mockMetrics[i].title);
+ });
+
+ // swap two elements and `input` them
+ [mockMetrics[0], mockMetrics[1]] = [mockMetrics[1], mockMetrics[0]];
+ firstDraggable.vm.$emit('input', mockMetrics);
+
+ firstDraggable.vm.$nextTick(() => {
+ value().forEach((metric, i) => {
+ expect(metric.title).toBe(mockMetrics[i].title);
+ });
+ done();
+ });
+ });
+
it('shows a remove button, which removes a panel', done => {
expect(findFirstDraggableRemoveButton().isEmpty()).toBe(false);
@@ -449,8 +471,6 @@ describe('Dashboard', () => {
findFirstDraggableRemoveButton().trigger('click');
wrapper.vm.$nextTick(() => {
- // At present graphs will not be removed in backend
- // See https://gitlab.com/gitlab-org/gitlab/issues/27835
expect(findDraggablePanels().length).toEqual(expectedPanelCount - 1);
done();
});
@@ -686,7 +706,9 @@ describe('Dashboard', () => {
`monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
MonitoringMock.data,
);
- [mockGraphData] = component.$store.state.monitoringDashboard.groups[0].metrics;
+ [
+ mockGraphData,
+ ] = component.$store.state.monitoringDashboard.dashboard.panel_groups[0].metrics;
});
describe('csvText', () => {
diff --git a/spec/javascripts/monitoring/store/actions_spec.js b/spec/javascripts/monitoring/store/actions_spec.js
index 1bd74f59282..4d602e3b0a2 100644
--- a/spec/javascripts/monitoring/store/actions_spec.js
+++ b/spec/javascripts/monitoring/store/actions_spec.js
@@ -291,9 +291,9 @@ describe('Monitoring store actions', () => {
it('dispatches fetchPrometheusMetric for each panel query', done => {
const params = {};
const state = storeState();
- state.groups = metricsDashboardResponse.dashboard.panel_groups;
+ state.dashboard.panel_groups = metricsDashboardResponse.dashboard.panel_groups;
- const metric = state.groups[0].panels[0].metrics[0];
+ const metric = state.dashboard.panel_groups[0].panels[0].metrics[0];
fetchPrometheusMetrics({ state, commit, dispatch }, params)
.then(() => {
diff --git a/spec/javascripts/monitoring/store/mutations_spec.js b/spec/javascripts/monitoring/store/mutations_spec.js
index bdddd83358c..49aed1b85e6 100644
--- a/spec/javascripts/monitoring/store/mutations_spec.js
+++ b/spec/javascripts/monitoring/store/mutations_spec.js
@@ -20,16 +20,26 @@ describe('Monitoring mutations', () => {
let groups;
beforeEach(() => {
- stateCopy.groups = [];
+ stateCopy.dashboard.panel_groups = [];
groups = metricsGroupsAPIResponse.data;
});
+ it('adds a key to the group', () => {
+ mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, groups);
+
+ expect(stateCopy.dashboard.panel_groups[0].key).toBe('kubernetes-0');
+ expect(stateCopy.dashboard.panel_groups[1].key).toBe('nginx-1');
+ });
+
it('normalizes values', () => {
mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, groups);
const expectedTimestamp = '2017-05-25T08:22:34.925Z';
- const expectedValue = 0.0010794445585559514;
- const [timestamp, value] = stateCopy.groups[0].metrics[0].queries[0].result[0].values[0];
+ const expectedValue = 8.0390625;
+ const [
+ timestamp,
+ value,
+ ] = stateCopy.dashboard.panel_groups[0].metrics[0].queries[0].result[0].values[0];
expect(timestamp).toEqual(expectedTimestamp);
expect(value).toEqual(expectedValue);
@@ -38,25 +48,25 @@ describe('Monitoring mutations', () => {
it('contains two groups that contains, one of which has two queries sorted by priority', () => {
mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, groups);
- expect(stateCopy.groups).toBeDefined();
- expect(stateCopy.groups.length).toEqual(2);
- expect(stateCopy.groups[0].metrics.length).toEqual(2);
+ expect(stateCopy.dashboard.panel_groups).toBeDefined();
+ expect(stateCopy.dashboard.panel_groups.length).toEqual(2);
+ expect(stateCopy.dashboard.panel_groups[0].metrics.length).toEqual(2);
});
it('assigns queries a metric id', () => {
mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, groups);
- expect(stateCopy.groups[1].metrics[0].queries[0].metricId).toEqual('100');
+ expect(stateCopy.dashboard.panel_groups[1].metrics[0].queries[0].metricId).toEqual('100');
});
it('removes the data if all the values from a query are not defined', () => {
mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, groups);
- expect(stateCopy.groups[1].metrics[0].queries[0].result.length).toEqual(0);
+ expect(stateCopy.dashboard.panel_groups[1].metrics[0].queries[0].result.length).toEqual(0);
});
it('assigns metric id of null if metric has no id', () => {
- stateCopy.groups = [];
+ stateCopy.dashboard.panel_groups = [];
const noId = groups.map(group => ({
...group,
...{
@@ -70,7 +80,7 @@ describe('Monitoring mutations', () => {
mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, noId);
- stateCopy.groups.forEach(group => {
+ stateCopy.dashboard.panel_groups.forEach(group => {
group.metrics.forEach(metric => {
expect(metric.queries.every(query => query.metricId === null)).toBe(true);
});
@@ -87,13 +97,13 @@ describe('Monitoring mutations', () => {
it('aliases group panels to metrics for backwards compatibility', () => {
mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, dashboardGroups);
- expect(stateCopy.groups[0].metrics[0]).toBeDefined();
+ expect(stateCopy.dashboard.panel_groups[0].metrics[0]).toBeDefined();
});
it('aliases panel metrics to queries for backwards compatibility', () => {
mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, dashboardGroups);
- expect(stateCopy.groups[0].metrics[0].queries).toBeDefined();
+ expect(stateCopy.dashboard.panel_groups[0].metrics[0].queries).toBeDefined();
});
});
});
diff --git a/spec/lib/gitlab/prometheus/internal_spec.rb b/spec/lib/gitlab/prometheus/internal_spec.rb
new file mode 100644
index 00000000000..884bdcb4e9b
--- /dev/null
+++ b/spec/lib/gitlab/prometheus/internal_spec.rb
@@ -0,0 +1,108 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Prometheus::Internal do
+ let(:listen_address) { 'localhost:9090' }
+
+ let(:prometheus_settings) do
+ {
+ enable: true,
+ listen_address: listen_address
+ }
+ end
+
+ before do
+ stub_config(prometheus: prometheus_settings)
+ end
+
+ describe '.uri' do
+ shared_examples 'returns valid uri' do |uri_string|
+ it do
+ expect(described_class.uri).to eq(uri_string)
+ expect { Addressable::URI.parse(described_class.uri) }.not_to raise_error
+ end
+ end
+
+ it_behaves_like 'returns valid uri', 'http://localhost:9090'
+
+ context 'with non default prometheus address' do
+ let(:listen_address) { 'https://localhost:9090' }
+
+ it_behaves_like 'returns valid uri', 'https://localhost:9090'
+
+ context 'with :9090 symbol' do
+ let(:listen_address) { :':9090' }
+
+ it_behaves_like 'returns valid uri', 'http://localhost:9090'
+ end
+
+ context 'with 0.0.0.0:9090' do
+ let(:listen_address) { '0.0.0.0:9090' }
+
+ it_behaves_like 'returns valid uri', 'http://localhost:9090'
+ end
+ end
+
+ context 'when listen_address is nil' do
+ let(:listen_address) { nil }
+
+ it 'does not fail' do
+ expect(described_class.uri).to eq(nil)
+ end
+ end
+
+ context 'when prometheus listen address is blank in gitlab.yml' do
+ let(:listen_address) { '' }
+
+ it 'does not configure prometheus' do
+ expect(described_class.uri).to eq(nil)
+ end
+ end
+ end
+
+ describe 'prometheus_enabled?' do
+ it 'returns correct value' do
+ expect(described_class.prometheus_enabled?).to eq(true)
+ end
+
+ context 'when prometheus setting is disabled in gitlab.yml' do
+ let(:prometheus_settings) do
+ {
+ enable: false,
+ listen_address: listen_address
+ }
+ end
+
+ it 'returns correct value' do
+ expect(described_class.prometheus_enabled?).to eq(false)
+ end
+ end
+
+ context 'when prometheus setting is not present in gitlab.yml' do
+ before do
+ allow(Gitlab.config).to receive(:prometheus).and_raise(Settingslogic::MissingSetting)
+ end
+
+ it 'does not fail' do
+ expect(described_class.prometheus_enabled?).to eq(false)
+ end
+ end
+ end
+
+ describe '.listen_address' do
+ it 'returns correct value' do
+ expect(described_class.listen_address).to eq(listen_address)
+ end
+
+ context 'when prometheus setting is not present in gitlab.yml' do
+ before do
+ allow(Gitlab.config).to receive(:prometheus).and_raise(Settingslogic::MissingSetting)
+ end
+
+ it 'does not fail' do
+ expect(described_class.listen_address).to eq(nil)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb
new file mode 100644
index 00000000000..bd558edf9c5
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Setting milestone of a merge request' do
+ include GraphqlHelpers
+
+ let(:current_user) { create(:user) }
+ let(:merge_request) { create(:merge_request) }
+ let(:project) { merge_request.project }
+ let(:milestone) { create(:milestone, project: project) }
+ let(:input) { { milestone_id: GitlabSchema.id_from_object(milestone).to_s } }
+
+ let(:mutation) do
+ variables = {
+ project_path: project.full_path,
+ iid: merge_request.iid.to_s
+ }
+ graphql_mutation(:merge_request_set_milestone, variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ mergeRequest {
+ id
+ milestone {
+ id
+ }
+ }
+ QL
+ )
+ end
+
+ def mutation_response
+ graphql_mutation_response(:merge_request_set_milestone)
+ end
+
+ before do
+ project.add_developer(current_user)
+ end
+
+ it 'returns an error if the user is not allowed to update the merge request' do
+ post_graphql_mutation(mutation, current_user: create(:user))
+
+ expect(graphql_errors).not_to be_empty
+ end
+
+ it 'sets the merge request milestone' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['mergeRequest']['milestone']['id']).to eq(milestone.to_global_id.to_s)
+ end
+
+ context 'when passing milestone_id nil as input' do
+ let(:input) { { milestone_id: nil } }
+
+ it 'removes the merge request milestone' do
+ merge_request.update!(milestone: milestone)
+
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['mergeRequest']['milestone']).to be_nil
+ end
+ end
+end
diff --git a/spec/support/helpers/kubernetes_helpers.rb b/spec/support/helpers/kubernetes_helpers.rb
index e74dbca4f93..199156c53d7 100644
--- a/spec/support/helpers/kubernetes_helpers.rb
+++ b/spec/support/helpers/kubernetes_helpers.rb
@@ -319,10 +319,10 @@ module KubernetesHelpers
}
end
- def kube_knative_services_body(legacy_knative: false, **options)
+ def kube_knative_services_body(**options)
{
"kind" => "List",
- "items" => [legacy_knative ? knative_05_service(options) : kube_service(options)]
+ "items" => [knative_07_service(options)]
}
end
@@ -398,77 +398,171 @@ module KubernetesHelpers
}
end
- def kube_service(name: "kubetest", namespace: "default", domain: "example.com")
- {
- "metadata" => {
- "creationTimestamp" => "2018-11-21T06:16:33Z",
- "name" => name,
- "namespace" => namespace,
- "selfLink" => "/apis/serving.knative.dev/v1alpha1/namespaces/#{namespace}/services/#{name}"
- },
+ # noinspection RubyStringKeysInHashInspection
+ def knative_06_service(name: 'kubetest', namespace: 'default', domain: 'example.com', description: 'a knative service', environment: 'production')
+ { "apiVersion" => "serving.knative.dev/v1alpha1",
+ "kind" => "Service",
+ "metadata" =>
+ { "annotations" =>
+ { "serving.knative.dev/creator" => "system:serviceaccount:#{namespace}:#{namespace}-service-account",
+ "serving.knative.dev/lastModifier" => "system:serviceaccount:#{namespace}:#{namespace}-service-account" },
+ "creationTimestamp" => "2019-10-22T21:19:20Z",
+ "generation" => 1,
+ "labels" => { "service" => name },
+ "name" => name,
+ "namespace" => namespace,
+ "resourceVersion" => "6042",
+ "selfLink" => "/apis/serving.knative.dev/v1alpha1/namespaces/#{namespace}/services/#{name}",
+ "uid" => "9c7f63d0-f511-11e9-8815-42010a80002f" },
"spec" => {
- "generation" => 2
+ "runLatest" => {
+ "configuration" => {
+ "revisionTemplate" => {
+ "metadata" => {
+ "annotations" => { "Description" => description },
+ "creationTimestamp" => "2019-10-22T21:19:20Z",
+ "labels" => { "service" => name }
+ },
+ "spec" => {
+ "container" => {
+ "env" => [{ "name" => "timestamp", "value" => "2019-10-22 21:19:20" }],
+ "image" => "image_name",
+ "name" => "",
+ "resources" => {}
+ },
+ "timeoutSeconds" => 300
+ }
+ }
+ }
+ }
},
"status" => {
- "url" => "http://#{name}.#{namespace}.#{domain}",
"address" => {
- "url" => "#{name}.#{namespace}.svc.cluster.local"
+ "hostname" => "#{name}.#{namespace}.svc.cluster.local",
+ "url" => "http://#{name}.#{namespace}.svc.cluster.local"
},
- "latestCreatedRevisionName" => "#{name}-00002",
- "latestReadyRevisionName" => "#{name}-00002",
- "observedGeneration" => 2
- }
- }
- end
-
- def knative_05_service(name: "kubetest", namespace: "default", domain: "example.com")
- {
- "metadata" => {
- "creationTimestamp" => "2018-11-21T06:16:33Z",
- "name" => name,
- "namespace" => namespace,
- "selfLink" => "/apis/serving.knative.dev/v1alpha1/namespaces/#{namespace}/services/#{name}"
- },
- "spec" => {
- "generation" => 2
- },
- "status" => {
+ "conditions" =>
+ [{ "lastTransitionTime" => "2019-10-22T21:20:25Z", "status" => "True", "type" => "ConfigurationsReady" },
+ { "lastTransitionTime" => "2019-10-22T21:20:25Z", "status" => "True", "type" => "Ready" },
+ { "lastTransitionTime" => "2019-10-22T21:20:25Z", "status" => "True", "type" => "RoutesReady" }],
"domain" => "#{name}.#{namespace}.#{domain}",
"domainInternal" => "#{name}.#{namespace}.svc.cluster.local",
- "latestCreatedRevisionName" => "#{name}-00002",
- "latestReadyRevisionName" => "#{name}-00002",
- "observedGeneration" => 2
- }
- }
- end
-
- def kube_service_full(name: "kubetest", namespace: "kube-ns", domain: "example.com")
- {
- "metadata" => {
- "creationTimestamp" => "2018-11-21T06:16:33Z",
- "name" => name,
- "namespace" => namespace,
- "selfLink" => "/apis/serving.knative.dev/v1alpha1/namespaces/#{namespace}/services/#{name}",
- "annotation" => {
- "description" => "This is a test description"
- }
+ "latestCreatedRevisionName" => "#{name}-bskx6",
+ "latestReadyRevisionName" => "#{name}-bskx6",
+ "observedGeneration" => 1,
+ "traffic" => [{ "latestRevision" => true, "percent" => 100, "revisionName" => "#{name}-bskx6" }],
+ "url" => "http://#{name}.#{namespace}.#{domain}"
},
+ "environment_scope" => environment,
+ "cluster_id" => 9,
+ "podcount" => 0 }
+ end
+
+ # noinspection RubyStringKeysInHashInspection
+ def knative_07_service(name: 'kubetest', namespace: 'default', domain: 'example.com', description: 'a knative service', environment: 'production')
+ { "apiVersion" => "serving.knative.dev/v1alpha1",
+ "kind" => "Service",
+ "metadata" =>
+ { "annotations" =>
+ { "serving.knative.dev/creator" => "system:serviceaccount:#{namespace}:#{namespace}-service-account",
+ "serving.knative.dev/lastModifier" => "system:serviceaccount:#{namespace}:#{namespace}-service-account" },
+ "creationTimestamp" => "2019-10-22T21:19:13Z",
+ "generation" => 1,
+ "labels" => { "service" => name },
+ "name" => name,
+ "namespace" => namespace,
+ "resourceVersion" => "289726",
+ "selfLink" => "/apis/serving.knative.dev/v1alpha1/namespaces/#{namespace}/services/#{name}",
+ "uid" => "988349fa-f511-11e9-9ea1-42010a80005e" },
"spec" => {
- "generation" => 2,
- "build" => {
- "template" => "go-1.10.3"
+ "template" => {
+ "metadata" => {
+ "annotations" => { "Description" => description },
+ "creationTimestamp" => "2019-10-22T21:19:12Z",
+ "labels" => { "service" => name }
+ },
+ "spec" => {
+ "containers" => [{
+ "env" =>
+ [{ "name" => "timestamp", "value" => "2019-10-22 21:19:12" }],
+ "image" => "image_name",
+ "name" => "user-container",
+ "resources" => {}
+ }],
+ "timeoutSeconds" => 300
+ }
+ },
+ "traffic" => [{ "latestRevision" => true, "percent" => 100 }]
+ },
+ "status" =>
+ { "address" => { "url" => "http://#{name}.#{namespace}.svc.cluster.local" },
+ "conditions" =>
+ [{ "lastTransitionTime" => "2019-10-22T21:20:15Z", "status" => "True", "type" => "ConfigurationsReady" },
+ { "lastTransitionTime" => "2019-10-22T21:20:15Z", "status" => "True", "type" => "Ready" },
+ { "lastTransitionTime" => "2019-10-22T21:20:15Z", "status" => "True", "type" => "RoutesReady" }],
+ "latestCreatedRevisionName" => "#{name}-92tsj",
+ "latestReadyRevisionName" => "#{name}-92tsj",
+ "observedGeneration" => 1,
+ "traffic" => [{ "latestRevision" => true, "percent" => 100, "revisionName" => "#{name}-92tsj" }],
+ "url" => "http://#{name}.#{namespace}.#{domain}" },
+ "environment_scope" => environment,
+ "cluster_id" => 5,
+ "podcount" => 0 }
+ end
+
+ # noinspection RubyStringKeysInHashInspection
+ def knative_05_service(name: 'kubetest', namespace: 'default', domain: 'example.com', description: 'a knative service', environment: 'production')
+ { "apiVersion" => "serving.knative.dev/v1alpha1",
+ "kind" => "Service",
+ "metadata" =>
+ { "annotations" =>
+ { "serving.knative.dev/creator" => "system:serviceaccount:#{namespace}:#{namespace}-service-account",
+ "serving.knative.dev/lastModifier" => "system:serviceaccount:#{namespace}:#{namespace}-service-account" },
+ "creationTimestamp" => "2019-10-22T21:19:19Z",
+ "generation" => 1,
+ "labels" => { "service" => name },
+ "name" => name,
+ "namespace" => namespace,
+ "resourceVersion" => "330390",
+ "selfLink" => "/apis/serving.knative.dev/v1alpha1/namespaces/#{namespace}/services/#{name}",
+ "uid" => "9c710da6-f511-11e9-9ba0-42010a800161" },
+ "spec" => {
+ "runLatest" => {
+ "configuration" => {
+ "revisionTemplate" => {
+ "metadata" => {
+ "annotations" => { "Description" => description },
+ "creationTimestamp" => "2019-10-22T21:19:19Z",
+ "labels" => { "service" => name }
+ },
+ "spec" => {
+ "container" => {
+ "env" => [{ "name" => "timestamp", "value" => "2019-10-22 21:19:19" }],
+ "image" => "image_name",
+ "name" => "",
+ "resources" => { "requests" => { "cpu" => "400m" } }
+ },
+ "timeoutSeconds" => 300
+ }
+ }
+ }
}
},
- "status" => {
- "url" => "http://#{name}.#{namespace}.#{domain}",
- "address" => {
- "url" => "#{name}.#{namespace}.svc.cluster.local"
- },
- "latestCreatedRevisionName" => "#{name}-00002",
- "latestReadyRevisionName" => "#{name}-00002",
- "observedGeneration" => 2
- }
- }
+ "status" =>
+ { "address" => { "hostname" => "#{name}.#{namespace}.svc.cluster.local" },
+ "conditions" =>
+ [{ "lastTransitionTime" => "2019-10-22T21:20:24Z", "status" => "True", "type" => "ConfigurationsReady" },
+ { "lastTransitionTime" => "2019-10-22T21:20:24Z", "status" => "True", "type" => "Ready" },
+ { "lastTransitionTime" => "2019-10-22T21:20:24Z", "status" => "True", "type" => "RoutesReady" }],
+ "domain" => "#{name}.#{namespace}.#{domain}",
+ "domainInternal" => "#{name}.#{namespace}.svc.cluster.local",
+ "latestCreatedRevisionName" => "#{name}-58qgr",
+ "latestReadyRevisionName" => "#{name}-58qgr",
+ "observedGeneration" => 1,
+ "traffic" => [{ "percent" => 100, "revisionName" => "#{name}-58qgr" }] },
+ "environment_scope" => environment,
+ "cluster_id" => 8,
+ "podcount" => 0 }
end
def kube_terminals(service, pod)