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>2021-08-24 00:11:23 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-08-24 00:11:23 +0300
commit0510f42da38bb0eb1d06aeb82b4d16ed71135776 (patch)
treeb83ce9d25ff8bf1938c44e51916fd5bd86e5ee8b
parent5e9fe672fa0eda6322bd392e8502d1886804bd07 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/pipelines/components/graph/accessors.js25
-rw-r--r--app/assets/javascripts/pipelines/components/graph/constants.js3
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_item.vue14
-rw-r--r--app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue29
-rw-r--r--app/assets/javascripts/pipelines/components/graph/stage_column_component.vue4
-rw-r--r--app/assets/javascripts/pipelines/pipeline_details_graph.js2
-rw-r--r--app/finders/groups/user_groups_finder.rb60
-rw-r--r--app/graphql/resolvers/base_resolver.rb10
-rw-r--r--app/graphql/resolvers/users/groups_resolver.rb44
-rw-r--r--app/graphql/types/permission_types/group.rb2
-rw-r--r--app/graphql/types/permission_types/group_enum.rb12
-rw-r--r--app/graphql/types/user_interface.rb3
-rw-r--r--app/helpers/issues_helper.rb6
-rw-r--r--app/models/preloaders/user_max_access_level_in_groups_preloader.rb27
-rw-r--r--app/policies/user_policy.rb1
-rw-r--r--config/feature_flags/development/paginatable_namespace_drop_down_for_project_creation.yml8
-rw-r--r--doc/api/graphql/reference/index.md77
-rw-r--r--doc/user/admin_area/settings/visibility_and_access_controls.md8
-rw-r--r--doc/user/application_security/configuration/index.md65
-rw-r--r--doc/user/group/index.md14
-rw-r--r--lib/gitlab/graphql/authorize/connection_filter_extension.rb15
-rw-r--r--locale/gitlab.pot3
-rw-r--r--spec/features/incidents/user_views_incident_spec.rb2
-rw-r--r--spec/features/issues/user_views_issue_spec.rb2
-rw-r--r--spec/finders/groups/user_groups_finder_spec.rb106
-rw-r--r--spec/frontend/pipelines/graph/graph_component_spec.js5
-rw-r--r--spec/frontend/pipelines/graph/job_item_spec.js36
-rw-r--r--spec/frontend/pipelines/graph/linked_pipeline_spec.js44
-rw-r--r--spec/frontend/pipelines/graph/linked_pipelines_column_spec.js4
-rw-r--r--spec/frontend/pipelines/graph/linked_pipelines_mock_data.js3812
-rw-r--r--spec/graphql/resolvers/users/groups_resolver_spec.rb106
-rw-r--r--spec/graphql/types/merge_requests/reviewer_type_spec.rb1
-rw-r--r--spec/graphql/types/user_type_spec.rb1
-rw-r--r--spec/helpers/issues_helper_spec.rb2
-rw-r--r--spec/models/preloaders/user_max_access_level_in_groups_preloader_spec.rb51
-rw-r--r--spec/policies/user_policy_spec.rb46
-rw-r--r--spec/requests/api/graphql/current_user/groups_query_spec.rb112
38 files changed, 799 insertions, 3965 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 9d553e5d555..11fe5bfe9bb 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-2ed9a2c78ec556eb8d64e03203c864355ea5a128
+bb2e3f4a916f031f38c9fb1c4fc955f50f0e4275
diff --git a/app/assets/javascripts/pipelines/components/graph/accessors.js b/app/assets/javascripts/pipelines/components/graph/accessors.js
deleted file mode 100644
index 6ece855bcd8..00000000000
--- a/app/assets/javascripts/pipelines/components/graph/accessors.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import { get } from 'lodash';
-import { REST, GRAPHQL } from './constants';
-
-const accessors = {
- [REST]: {
- detailsPath: 'details_path',
- groupId: 'id',
- hasDetails: 'has_details',
- pipelineStatus: ['details', 'status'],
- sourceJob: ['source_job', 'name'],
- },
- [GRAPHQL]: {
- detailsPath: 'detailsPath',
- groupId: 'name',
- hasDetails: 'hasDetails',
- pipelineStatus: 'status',
- sourceJob: ['sourceJob', 'name'],
- },
-};
-
-const accessValue = (dataMethod, prop, item) => {
- return get(item, accessors[dataMethod][prop]);
-};
-
-export { accessors, accessValue };
diff --git a/app/assets/javascripts/pipelines/components/graph/constants.js b/app/assets/javascripts/pipelines/components/graph/constants.js
index dd9cdae518f..0b59612b25c 100644
--- a/app/assets/javascripts/pipelines/components/graph/constants.js
+++ b/app/assets/javascripts/pipelines/components/graph/constants.js
@@ -8,9 +8,6 @@ export const UPSTREAM = 'upstream';
*/
export const ONE_COL_WIDTH = 180;
-export const REST = 'rest';
-export const GRAPHQL = 'graphql';
-
export const STAGE_VIEW = 'stage';
export const LAYER_VIEW = 'layer';
export const VIEW_TYPE_KEY = 'pipeline_graph_view_type';
diff --git a/app/assets/javascripts/pipelines/components/graph/job_item.vue b/app/assets/javascripts/pipelines/components/graph/job_item.vue
index 6584d89d87c..55088c70c33 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_item.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_item.vue
@@ -7,8 +7,7 @@ import CiIcon from '~/vue_shared/components/ci_icon.vue';
import { reportToSentry } from '../../utils';
import ActionComponent from '../jobs_shared/action_component.vue';
import JobNameComponent from '../jobs_shared/job_name_component.vue';
-import { accessValue } from './accessors';
-import { REST, SINGLE_JOB } from './constants';
+import { SINGLE_JOB } from './constants';
/**
* Renders the badge for the pipeline graph and the job's dropdown.
@@ -47,11 +46,6 @@ export default {
GlTooltip: GlTooltipDirective,
},
mixins: [delayedJobMixin],
- inject: {
- dataMethod: {
- default: REST,
- },
- },
props: {
job: {
type: Object,
@@ -111,10 +105,10 @@ export default {
return this.pipelineId > -1 ? `${this.job.name}-${this.pipelineId}` : '';
},
detailsPath() {
- return accessValue(this.dataMethod, 'detailsPath', this.status);
+ return this.status.detailsPath;
},
hasDetails() {
- return accessValue(this.dataMethod, 'hasDetails', this.status);
+ return this.status.hasDetails;
},
isSingleItem() {
return this.type === SINGLE_JOB;
@@ -189,7 +183,7 @@ export default {
if (this.isSingleItem) {
/*
This is so the jobDropdown still toggles. Issue to refactor:
- https://gitlab.com/gitlab-org/gitlab/-/issues/267117
+ https://gitlab.com/gitlab-org/gitlab/-/issues/267117
*/
evt.stopPropagation();
}
diff --git a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue
index dd8a354511a..ac038575387 100644
--- a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue
+++ b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue
@@ -4,8 +4,7 @@ import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { __, sprintf } from '~/locale';
import CiStatus from '~/vue_shared/components/ci_icon.vue';
import { reportToSentry } from '../../utils';
-import { accessValue } from './accessors';
-import { DOWNSTREAM, REST, UPSTREAM } from './constants';
+import { DOWNSTREAM, UPSTREAM } from './constants';
export default {
directives: {
@@ -18,11 +17,6 @@ export default {
GlLoadingIcon,
GlBadge,
},
- inject: {
- dataMethod: {
- default: REST,
- },
- },
props: {
columnTitle: {
type: String,
@@ -40,20 +34,9 @@ export default {
type: String,
required: true,
},
- /*
- The next two props will be removed or required
- once the graph transition is done.
- See: https://gitlab.com/gitlab-org/gitlab/-/issues/291043
- */
isLoading: {
type: Boolean,
- required: false,
- default: false,
- },
- projectId: {
- type: Number,
- required: false,
- default: -1,
+ required: true,
},
},
computed: {
@@ -65,7 +48,7 @@ export default {
return `js-linked-pipeline-${this.pipeline.id}`;
},
pipelineStatus() {
- return accessValue(this.dataMethod, 'pipelineStatus', this.pipeline);
+ return this.pipeline.status;
},
projectName() {
return this.pipeline.project.name;
@@ -97,12 +80,10 @@ export default {
return this.type === UPSTREAM;
},
isSameProject() {
- return this.projectId > -1
- ? this.projectId === this.pipeline.project.id
- : !this.pipeline.multiproject;
+ return !this.pipeline.multiproject;
},
sourceJobName() {
- return accessValue(this.dataMethod, 'sourceJob', this.pipeline);
+ return this.pipeline.sourceJob?.name ?? '';
},
sourceJobInfo() {
return this.isDownstream ? sprintf(__('Created by %{job}'), { job: this.sourceJobName }) : '';
diff --git a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
index d34ae8036ed..c91e88dbd5b 100644
--- a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
@@ -4,8 +4,6 @@ import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { reportToSentry } from '../../utils';
import MainGraphWrapper from '../graph_shared/main_graph_wrapper.vue';
import ActionComponent from '../jobs_shared/action_component.vue';
-import { accessValue } from './accessors';
-import { GRAPHQL } from './constants';
import JobGroupDropdown from './job_group_dropdown.vue';
import JobItem from './job_item.vue';
@@ -97,7 +95,7 @@ export default {
},
methods: {
getGroupId(group) {
- return accessValue(GRAPHQL, 'groupId', group);
+ return group.name;
},
groupId(group) {
return `ci-badge-${escape(group.name)}`;
diff --git a/app/assets/javascripts/pipelines/pipeline_details_graph.js b/app/assets/javascripts/pipelines/pipeline_details_graph.js
index 39c3c2ea5c5..9dd5cd7b281 100644
--- a/app/assets/javascripts/pipelines/pipeline_details_graph.js
+++ b/app/assets/javascripts/pipelines/pipeline_details_graph.js
@@ -1,6 +1,5 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
-import { GRAPHQL } from './components/graph/constants';
import PipelineGraphWrapper from './components/graph/graph_component_wrapper.vue';
import { reportToSentry } from './utils';
@@ -23,7 +22,6 @@ const createPipelinesDetailApp = (
pipelineProjectPath,
pipelineIid,
graphqlResourceEtag,
- dataMethod: GRAPHQL,
},
errorCaptured(err, _vm, info) {
reportToSentry('pipeline_details_graph', `error: ${err}, info: ${info}`);
diff --git a/app/finders/groups/user_groups_finder.rb b/app/finders/groups/user_groups_finder.rb
new file mode 100644
index 00000000000..5946e3a8933
--- /dev/null
+++ b/app/finders/groups/user_groups_finder.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+# Groups::UserGroupsFinder
+#
+# Used to filter Groups where a user is member
+#
+# Arguments:
+# current_user - user requesting group info on target user
+# target_user - user for which groups will be found
+# params:
+# permissions: string (see Types::Groups::UserPermissionsEnum)
+# search: string used for search on path and group name
+#
+# Initially created to filter user groups and descendants where the user can create projects
+module Groups
+ class UserGroupsFinder
+ def initialize(current_user, target_user, params = {})
+ @current_user = current_user
+ @target_user = target_user
+ @params = params
+ end
+
+ def execute
+ return Group.none unless current_user&.can?(:read_user_groups, target_user)
+ return Group.none if target_user.blank?
+
+ items = by_permission_scope
+ items = by_search(items)
+
+ sort(items)
+ end
+
+ private
+
+ attr_reader :current_user, :target_user, :params
+
+ def sort(items)
+ items.order(path: :asc, id: :asc) # rubocop: disable CodeReuse/ActiveRecord
+ end
+
+ def by_search(items)
+ return items if params[:search].blank?
+
+ items.search(params[:search])
+ end
+
+ def by_permission_scope
+ if permission_scope_create_projects?
+ target_user.manageable_groups(include_groups_with_developer_maintainer_access: true)
+ else
+ target_user.groups
+ end
+ end
+
+ def permission_scope_create_projects?
+ params[:permission_scope] == :create_projects &&
+ Feature.enabled?(:paginatable_namespace_drop_down_for_project_creation, current_user, default_enabled: :yaml)
+ end
+ end
+end
diff --git a/app/graphql/resolvers/base_resolver.rb b/app/graphql/resolvers/base_resolver.rb
index 48563633d11..20ed089d159 100644
--- a/app/graphql/resolvers/base_resolver.rb
+++ b/app/graphql/resolvers/base_resolver.rb
@@ -124,6 +124,16 @@ module Resolvers
[args[:iid], args[:iids]].any? ? 0 : 0.01
end
+ def self.before_connection_authorization(&block)
+ @before_connection_authorization_block = block
+ end
+
+ # rubocop: disable Style/TrivialAccessors
+ def self.before_connection_authorization_block
+ @before_connection_authorization_block
+ end
+ # rubocop: enable Style/TrivialAccessors
+
def offset_pagination(relation)
::Gitlab::Graphql::Pagination::OffsetPaginatedRelation.new(relation)
end
diff --git a/app/graphql/resolvers/users/groups_resolver.rb b/app/graphql/resolvers/users/groups_resolver.rb
new file mode 100644
index 00000000000..0899b08e19c
--- /dev/null
+++ b/app/graphql/resolvers/users/groups_resolver.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Users
+ class GroupsResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+ include LooksAhead
+
+ type Types::GroupType.connection_type, null: true
+
+ authorize :read_user_groups
+ authorizes_object!
+
+ argument :search, GraphQL::Types::String,
+ required: false,
+ description: 'Search by group name or path.'
+ argument :permission_scope,
+ ::Types::PermissionTypes::GroupEnum,
+ required: false,
+ description: 'Filter by permissions the user has on groups.'
+
+ before_connection_authorization do |nodes, current_user|
+ Preloaders::UserMaxAccessLevelInGroupsPreloader.new(nodes, current_user).execute
+ end
+
+ def resolve_with_lookahead(**args)
+ return unless Feature.enabled?(:paginatable_namespace_drop_down_for_project_creation, current_user, default_enabled: :yaml)
+
+ apply_lookahead(Groups::UserGroupsFinder.new(current_user, object, args).execute)
+ end
+
+ private
+
+ def preloads
+ {
+ path: [:route],
+ full_path: [:route]
+ }
+ end
+ end
+ end
+end
+
+Resolvers::Users::GroupsResolver.prepend_mod_with('Resolvers::Users::GroupsResolver')
diff --git a/app/graphql/types/permission_types/group.rb b/app/graphql/types/permission_types/group.rb
index 29833993ce6..6a1031e2532 100644
--- a/app/graphql/types/permission_types/group.rb
+++ b/app/graphql/types/permission_types/group.rb
@@ -5,7 +5,7 @@ module Types
class Group < BasePermissionType
graphql_name 'GroupPermissions'
- abilities :read_group
+ abilities :read_group, :create_projects
end
end
end
diff --git a/app/graphql/types/permission_types/group_enum.rb b/app/graphql/types/permission_types/group_enum.rb
new file mode 100644
index 00000000000..cc4f5e9f1f0
--- /dev/null
+++ b/app/graphql/types/permission_types/group_enum.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Types
+ module PermissionTypes
+ class GroupEnum < BaseEnum
+ graphql_name 'GroupPermission'
+ description 'User permission on groups'
+
+ value 'CREATE_PROJECTS', value: :create_projects, description: 'Groups where the user can create projects.'
+ end
+ end
+end
diff --git a/app/graphql/types/user_interface.rb b/app/graphql/types/user_interface.rb
index 71c6b7f3019..47a25e09c7d 100644
--- a/app/graphql/types/user_interface.rb
+++ b/app/graphql/types/user_interface.rb
@@ -59,6 +59,9 @@ module Types
type: Types::GroupMemberType.connection_type,
null: true,
description: 'Group memberships of the user.'
+ field :groups,
+ resolver: Resolvers::Users::GroupsResolver,
+ description: 'Groups where the user has access.'
field :group_count,
resolver: Resolvers::Users::GroupCountResolver,
description: 'Group count for the user.'
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index bbafdac9a7f..152d813daea 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -174,7 +174,11 @@ module IssuesHelper
end
def issue_header_actions_data(project, issuable, current_user)
- new_issuable_params = ({ issuable_template: 'incident', issue: { issue_type: 'incident' } } if issuable.incident?)
+ new_issuable_params = { issue: { description: _('Related to #%{issue_id}.') % { issue_id: issuable.iid } + "\n\n" } }
+ if issuable.incident?
+ new_issuable_params[:issuable_template] = 'incident'
+ new_issuable_params[:issue][:issue_type] = 'incident'
+ end
{
can_create_issue: show_new_issue_link?(project).to_s,
diff --git a/app/models/preloaders/user_max_access_level_in_groups_preloader.rb b/app/models/preloaders/user_max_access_level_in_groups_preloader.rb
new file mode 100644
index 00000000000..14f1d271572
--- /dev/null
+++ b/app/models/preloaders/user_max_access_level_in_groups_preloader.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Preloaders
+ # This class preloads the max access level (role) for the user within the given groups and
+ # stores the values in requests store.
+ # Will only be able to preload max access level for groups where the user is a direct member
+ class UserMaxAccessLevelInGroupsPreloader
+ include BulkMemberAccessLoad
+
+ def initialize(groups, user)
+ @groups = groups
+ @user = user
+ end
+
+ def execute
+ group_memberships = GroupMember.active_without_invites_and_requests
+ .non_minimal_access
+ .where(user: @user, source_id: @groups)
+ .group(:source_id)
+ .maximum(:access_level)
+
+ group_memberships.each do |group_id, max_access_level|
+ merge_value_to_request_store(User, @user.id, group_id, max_access_level)
+ end
+ end
+ end
+end
diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb
index 067f0f6a9d2..018c061af9f 100644
--- a/app/policies/user_policy.rb
+++ b/app/policies/user_policy.rb
@@ -25,6 +25,7 @@ class UserPolicy < BasePolicy
enable :update_user_status
enable :read_user_personal_access_tokens
enable :read_group_count
+ enable :read_user_groups
end
rule { default }.enable :read_user_profile
diff --git a/config/feature_flags/development/paginatable_namespace_drop_down_for_project_creation.yml b/config/feature_flags/development/paginatable_namespace_drop_down_for_project_creation.yml
new file mode 100644
index 00000000000..297a4f65aa4
--- /dev/null
+++ b/config/feature_flags/development/paginatable_namespace_drop_down_for_project_creation.yml
@@ -0,0 +1,8 @@
+---
+name: paginatable_namespace_drop_down_for_project_creation
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66112
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/338930
+milestone: '14.3'
+type: development
+group: group::project management
+default_enabled: false
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 4af7b8e9077..46506750e26 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -10176,6 +10176,7 @@ Represents a Group Membership.
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="grouppermissionscreateprojects"></a>`createProjects` | [`Boolean!`](#boolean) | Indicates the user can perform `create_projects` on this resource. |
| <a id="grouppermissionsreadgroup"></a>`readGroup` | [`Boolean!`](#boolean) | Indicates the user can perform `read_group` on this resource. |
### `GroupReleaseStats`
@@ -10910,6 +10911,23 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="mergerequestassigneeauthoredmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="mergerequestassigneeauthoredmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
+##### `MergeRequestAssignee.groups`
+
+Groups where the user has access.
+
+Returns [`GroupConnection`](#groupconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mergerequestassigneegroupspermissionscope"></a>`permissionScope` | [`GroupPermission`](#grouppermission) | Filter by permissions the user has on groups. |
+| <a id="mergerequestassigneegroupssearch"></a>`search` | [`String`](#string) | Search by group name or path. |
+
##### `MergeRequestAssignee.reviewRequestedMergeRequests`
Merge requests assigned to the user for review.
@@ -11139,6 +11157,23 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="mergerequestreviewerauthoredmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="mergerequestreviewerauthoredmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
+##### `MergeRequestReviewer.groups`
+
+Groups where the user has access.
+
+Returns [`GroupConnection`](#groupconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mergerequestreviewergroupspermissionscope"></a>`permissionScope` | [`GroupPermission`](#grouppermission) | Filter by permissions the user has on groups. |
+| <a id="mergerequestreviewergroupssearch"></a>`search` | [`String`](#string) | Search by group name or path. |
+
##### `MergeRequestReviewer.reviewRequestedMergeRequests`
Merge requests assigned to the user for review.
@@ -14010,6 +14045,23 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="usercoreauthoredmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="usercoreauthoredmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
+##### `UserCore.groups`
+
+Groups where the user has access.
+
+Returns [`GroupConnection`](#groupconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="usercoregroupspermissionscope"></a>`permissionScope` | [`GroupPermission`](#grouppermission) | Filter by permissions the user has on groups. |
+| <a id="usercoregroupssearch"></a>`search` | [`String`](#string) | Search by group name or path. |
+
##### `UserCore.reviewRequestedMergeRequests`
Merge requests assigned to the user for review.
@@ -15162,6 +15214,14 @@ Group member relation.
| <a id="groupmemberrelationdirect"></a>`DIRECT` | Members in the group itself. |
| <a id="groupmemberrelationinherited"></a>`INHERITED` | Members in the group's ancestor groups. |
+### `GroupPermission`
+
+User permission on groups.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="grouppermissioncreate_projects"></a>`CREATE_PROJECTS` | Groups where the user can create projects. |
+
### `HealthStatus`
Health status of an issue or epic.
@@ -16961,6 +17021,23 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="userauthoredmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="userauthoredmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
+###### `User.groups`
+
+Groups where the user has access.
+
+Returns [`GroupConnection`](#groupconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+####### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="usergroupspermissionscope"></a>`permissionScope` | [`GroupPermission`](#grouppermission) | Filter by permissions the user has on groups. |
+| <a id="usergroupssearch"></a>`search` | [`String`](#string) | Search by group name or path. |
+
###### `User.reviewRequestedMergeRequests`
Merge requests assigned to the user for review.
diff --git a/doc/user/admin_area/settings/visibility_and_access_controls.md b/doc/user/admin_area/settings/visibility_and_access_controls.md
index c46aec76e57..098c1ab20eb 100644
--- a/doc/user/admin_area/settings/visibility_and_access_controls.md
+++ b/doc/user/admin_area/settings/visibility_and_access_controls.md
@@ -98,15 +98,15 @@ delete a project. To allow only users with the Administrator role to delete proj
## Default delayed project deletion **(PREMIUM SELF)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/255449) in GitLab 14.2.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/255449) in GitLab 14.2 for groups created after August 12, 2021.
-Projects in a group (but not a personal namespace) can be deleted after a delayed period, by
-[configuring in Group Settings](../../group/index.md#enable-delayed-project-removal).
+Projects in a group (but not a personal namespace) can be deleted after a delayed period.
+You can [configure it in group settings](../../group/index.md#enable-delayed-project-removal).
To enable delayed project deletion by default in new groups:
1. Check the **Default delayed project deletion** checkbox.
-1. Click **Save changes**.
+1. Select **Save changes**.
## Default deletion delay **(PREMIUM SELF)**
diff --git a/doc/user/application_security/configuration/index.md b/doc/user/application_security/configuration/index.md
index 664fcd9b72f..98e241ba3bd 100644
--- a/doc/user/application_security/configuration/index.md
+++ b/doc/user/application_security/configuration/index.md
@@ -13,61 +13,56 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - A simplified version was made [available in all tiers](https://gitlab.com/gitlab-org/gitlab/-/issues/294076) in GitLab 13.10.
> - [Redesigned](https://gitlab.com/gitlab-org/gitlab/-/issues/326926) in 14.2.
-The Security Configuration page displays what security scans are available, links to documentation and also simple enablement tools for the current project.
+The Security Configuration page lists the following for the security testing and compliance tools:
-To view a project's security configuration, go to the project's home page,
-then in the left sidebar go to **Security & Compliance > Configuration**.
-
-For each security control the page displays:
-
-- Its name, description and a documentation link.
+- Name, description, and a documentation link.
- Whether or not it is available.
- A configuration button or a link to its configuration guide.
+The status of each security control is determined by the project's latest default branch
+[CI pipeline](../../../ci/pipelines/index.md).
+If a job with the expected security report artifact exists in the pipeline, the feature's status is
+_enabled_.
+
+If the latest pipeline used [Auto DevOps](../../../topics/autodevops/index.md),
+all security features are configured by default.
+
+To view a project's security configuration:
+
+1. On the top bar, select **Menu > Projects** and find your project.
+1. On the left sidebar, select **Security & Compliance > Configuration**.
+
+Select **Configuration history** to see the `.gitlab-ci.yml` file's history.
+
## Security testing
You can configure the following security controls:
-- Auto DevOps
- - Click **Enable Auto DevOps** on the alert to enable it for the current project. For more details, see [Auto DevOps](../../../topics/autodevops/index.md).
-- SAST
- - Click **Enable SAST** to use SAST for the current project. For more details, see [Configure SAST in the UI](../sast/index.md#configure-sast-in-the-ui).
-- DAST **(ULTIMATE)**
- - Click **Enable DAST** to use DAST for the current Project. To manage the available DAST profiles used for on-demand scans Click **Manage Scans**. For more details, see [DAST on-demand scans](../dast/index.md#on-demand-scans).
+- Static Application Security Testing (SAST)
+ - Select **Enable SAST** to configure SAST for the current project.
+ For more details, read [Configure SAST in the UI](../sast/index.md#configure-sast-in-the-ui).
+- Dynamic Application Security Testing (DAST) **(ULTIMATE)**
+ - Select **Enable DAST** to configure DAST for the current project.
+ - Select **Manage scans** to manage the saved DAST scans, site profiles, and scanner profiles.
+ For more details, read [DAST on-demand scans](../dast/index.md#on-demand-scans).
- Dependency Scanning **(ULTIMATE)**
- Select **Configure via Merge Request** to create a merge request with the changes required to
enable Dependency Scanning. For more details, see [Enable Dependency Scanning via an automatic merge request](../dependency_scanning/index.md#enable-dependency-scanning-via-an-automatic-merge-request).
-
- Container Scanning **(ULTIMATE)**
- - Can be configured via `.gitlab-ci.yml`. For more details, see [Container Scanning](../../../user/application_security/container_scanning/index.md#configuration).
+ - Can be configured with `.gitlab-ci.yml`. For more details, read [Container Scanning](../../../user/application_security/container_scanning/index.md#configuration).
- Cluster Image Scanning **(ULTIMATE)**
- - Can be configured via `.gitlab-ci.yml`. For more details, see [Cluster Image Scanning](../../../user/application_security/cluster_image_scanning/#configuration).
+ - Can be configured with `.gitlab-ci.yml`. For more details, read [Cluster Image Scanning](../../../user/application_security/cluster_image_scanning/#configuration).
- Secret Detection
- Select **Configure via Merge Request** to create a merge request with the changes required to
- enable Secret Detection. For more details, see [Enable Secret Detection via an automatic merge request](../secret_detection/index.md#enable-secret-detection-via-an-automatic-merge-request).
-
+ enable Secret Detection. For more details, read [Enable Secret Detection via an automatic merge request](../secret_detection/index.md#enable-secret-detection-via-an-automatic-merge-request).
- API Fuzzing **(ULTIMATE)**
- - Click **Enable API Fuzzing** to use API Fuzzing for the current Project. For more details, see [API Fuzzing](../../../user/application_security/api_fuzzing/index.md#enable-web-api-fuzzing).
+ - Select **Enable API Fuzzing** to use API Fuzzing for the current project. For more details, read [API Fuzzing](../../../user/application_security/api_fuzzing/index.md#enable-web-api-fuzzing).
- Coverage Fuzzing **(ULTIMATE)**
- - Can be configured via `.gitlab-ci.yml`. For more details, see [Coverage Fuzzing](../../../user/application_security/coverage_fuzzing/index.md#configuration).
-
-## Status **(ULTIMATE)**
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20711) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.6.
-
-The status of each security control is determined by the project's latest default branch
-[CI pipeline](../../../ci/pipelines/index.md).
-If a job with the expected security report artifact exists in the pipeline, the feature's status is
-_enabled_.
-
-If the latest pipeline used [Auto DevOps](../../../topics/autodevops/index.md),
-all security features are configured by default.
-
-Click **View history** to see the `.gitlab-ci.yml` file's history.
+ - Can be configured with `.gitlab-ci.yml`. For more details, read [Coverage Fuzzing](../../../user/application_security/coverage_fuzzing/index.md#configuration).
## Compliance **(ULTIMATE)**
You can configure the following security controls:
- License Compliance **(ULTIMATE)**
- - Can be configured via `.gitlab-ci.yml`. For more details, see [License Compliance](../../../user/compliance/license_compliance/index.md#configuration).
+ - Can be configured with `.gitlab-ci.yml`. For more details, read [License Compliance](../../../user/compliance/license_compliance/index.md#configuration).
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index 948f9cab659..d4b3b5fbff1 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -664,16 +664,16 @@ Projects can be configured to be deleted either:
- Immediately.
- After a delayed interval. During this interval period, the projects are in a read-only state
- and can be restored, if required. The default interval period is seven days but
+ and can be restored. The default interval period is seven days but
[is configurable](../admin_area/settings/visibility_and_access_controls.md#default-deletion-delay).
-On:
+On self-managed GitLab, projects are deleted immediately by default.
+In GitLab 14.2 and later, an administrator can
+[change the default setting](../admin_area/settings/visibility_and_access_controls.md#default-delayed-project-deletion)
+for projects in newly-created groups.
-- GitLab self-managed instances, projects are deleted immediately by default. In GitLab
- 14.2 and later, an administrator can
- [change the default setting](../admin_area/settings/visibility_and_access_controls.md#default-delayed-project-deletion) for projects in newly-created groups.
-- GitLab.com, see [GitLab.com settings page](../gitlab_com/index.md#delayed-project-deletion) for
- the default setting.
+On GitLab.com, see the [GitLab.com settings page](../gitlab_com/index.md#delayed-project-deletion) for
+the default setting.
To enable delayed deletion of projects in a group:
diff --git a/lib/gitlab/graphql/authorize/connection_filter_extension.rb b/lib/gitlab/graphql/authorize/connection_filter_extension.rb
index c75510df3e3..889c024ab5e 100644
--- a/lib/gitlab/graphql/authorize/connection_filter_extension.rb
+++ b/lib/gitlab/graphql/authorize/connection_filter_extension.rb
@@ -7,12 +7,14 @@ module Gitlab
class Redactor
include ::Gitlab::Graphql::Laziness
- def initialize(type, context)
+ def initialize(type, context, resolver)
@type = type
@context = context
+ @resolver = resolver
end
def redact(nodes)
+ perform_before_authorize_action(nodes)
remove_unauthorized(nodes)
nodes
@@ -29,6 +31,13 @@ module Gitlab
private
+ def perform_before_authorize_action(nodes)
+ before_connection_authorization_block = @resolver&.before_connection_authorization_block
+ return unless before_connection_authorization_block.respond_to?(:call)
+
+ before_connection_authorization_block.call(nodes, @context[:current_user])
+ end
+
def remove_unauthorized(nodes)
nodes
.map! { |lazy| force(lazy) }
@@ -49,14 +58,14 @@ module Gitlab
end
def redact_connection(conn, context)
- redactor = Redactor.new(@field.type.unwrap.node_type, context)
+ redactor = Redactor.new(@field.type.unwrap.node_type, context, @field.resolver)
return unless redactor.active?
conn.redactor = redactor if conn.respond_to?(:redactor=)
end
def redact_list(list, context)
- redactor = Redactor.new(@field.type.unwrap, context)
+ redactor = Redactor.new(@field.type.unwrap, context, @field.resolver)
redactor.redact(list) if redactor.active?
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e629b9d5ad8..7328d6ab0b3 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -27665,6 +27665,9 @@ msgstr ""
msgid "Related merge requests"
msgstr ""
+msgid "Related to #%{issue_id}."
+msgstr ""
+
msgid "Relates to"
msgstr ""
diff --git a/spec/features/incidents/user_views_incident_spec.rb b/spec/features/incidents/user_views_incident_spec.rb
index b94ce3cd06f..244b66f7a9a 100644
--- a/spec/features/incidents/user_views_incident_spec.rb
+++ b/spec/features/incidents/user_views_incident_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe "User views incident" do
it 'shows the merge request and incident actions', :js, :aggregate_failures do
click_button 'Incident actions'
- expect(page).to have_link('New incident', href: new_project_issue_path(project, { issuable_template: 'incident', issue: { issue_type: 'incident' } }))
+ expect(page).to have_link('New incident', href: new_project_issue_path(project, { issuable_template: 'incident', issue: { issue_type: 'incident', description: "Related to \##{incident.iid}.\n\n" } }))
expect(page).to have_button('Create merge request')
expect(page).to have_button('Close incident')
end
diff --git a/spec/features/issues/user_views_issue_spec.rb b/spec/features/issues/user_views_issue_spec.rb
index 8792d76981f..31bf7649470 100644
--- a/spec/features/issues/user_views_issue_spec.rb
+++ b/spec/features/issues/user_views_issue_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe "User views issue" do
it 'shows the merge request and issue actions', :js, :aggregate_failures do
click_button 'Issue actions'
- expect(page).to have_link('New issue', href: new_project_issue_path(project))
+ expect(page).to have_link('New issue', href: new_project_issue_path(project, { issue: { description: "Related to \##{issue.iid}.\n\n" } }))
expect(page).to have_button('Create merge request')
expect(page).to have_button('Close issue')
end
diff --git a/spec/finders/groups/user_groups_finder_spec.rb b/spec/finders/groups/user_groups_finder_spec.rb
new file mode 100644
index 00000000000..4cce3ab72eb
--- /dev/null
+++ b/spec/finders/groups/user_groups_finder_spec.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Groups::UserGroupsFinder do
+ describe '#execute' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:guest_group) { create(:group, name: 'public guest', path: 'public-guest') }
+ let_it_be(:private_maintainer_group) { create(:group, :private, name: 'b private maintainer', path: 'b-private-maintainer') }
+ let_it_be(:public_developer_group) { create(:group, project_creation_level: nil, name: 'c public developer', path: 'c-public-developer') }
+ let_it_be(:public_maintainer_group) { create(:group, name: 'a public maintainer', path: 'a-public-maintainer') }
+
+ subject { described_class.new(current_user, target_user, arguments).execute }
+
+ let(:arguments) { {} }
+ let(:current_user) { user }
+ let(:target_user) { user }
+
+ before_all do
+ guest_group.add_guest(user)
+ private_maintainer_group.add_maintainer(user)
+ public_developer_group.add_developer(user)
+ public_maintainer_group.add_maintainer(user)
+ end
+
+ it 'returns all groups where the user is a direct member' do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ private_maintainer_group,
+ public_developer_group,
+ guest_group
+ ]
+ )
+ end
+
+ context 'when target_user is nil' do
+ let(:target_user) { nil }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'when current_user is nil' do
+ let(:current_user) { nil }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'when permission is :create_projects' do
+ let(:arguments) { { permission_scope: :create_projects } }
+
+ specify do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ private_maintainer_group,
+ public_developer_group
+ ]
+ )
+ end
+
+ context 'when paginatable_namespace_drop_down_for_project_creation feature flag is disabled' do
+ before do
+ stub_feature_flags(paginatable_namespace_drop_down_for_project_creation: false)
+ end
+
+ it 'ignores project creation scope and returns all groups where the user is a direct member' do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ private_maintainer_group,
+ public_developer_group,
+ guest_group
+ ]
+ )
+ end
+ end
+
+ context 'when search is provided' do
+ let(:arguments) { { permission_scope: :create_projects, search: 'maintainer' } }
+
+ specify do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ private_maintainer_group
+ ]
+ )
+ end
+ end
+ end
+
+ context 'when search is provided' do
+ let(:arguments) { { search: 'maintainer' } }
+
+ specify do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ private_maintainer_group
+ ]
+ )
+ end
+ end
+ end
+end
diff --git a/spec/frontend/pipelines/graph/graph_component_spec.js b/spec/frontend/pipelines/graph/graph_component_spec.js
index 1fba3823161..4b2b61c8edd 100644
--- a/spec/frontend/pipelines/graph/graph_component_spec.js
+++ b/spec/frontend/pipelines/graph/graph_component_spec.js
@@ -1,5 +1,5 @@
import { mount, shallowMount } from '@vue/test-utils';
-import { GRAPHQL, LAYER_VIEW, STAGE_VIEW } from '~/pipelines/components/graph/constants';
+import { LAYER_VIEW, STAGE_VIEW } from '~/pipelines/components/graph/constants';
import PipelineGraph from '~/pipelines/components/graph/graph_component.vue';
import JobItem from '~/pipelines/components/graph/job_item.vue';
import LinkedPipelinesColumn from '~/pipelines/components/graph/linked_pipelines_column.vue';
@@ -54,9 +54,6 @@ describe('graph component', () => {
...data,
};
},
- provide: {
- dataMethod: GRAPHQL,
- },
stubs: {
'links-inner': true,
'linked-pipeline': true,
diff --git a/spec/frontend/pipelines/graph/job_item_spec.js b/spec/frontend/pipelines/graph/job_item_spec.js
index 4c7ea5edda9..cbc5d11403e 100644
--- a/spec/frontend/pipelines/graph/job_item_spec.js
+++ b/spec/frontend/pipelines/graph/job_item_spec.js
@@ -14,7 +14,29 @@ describe('pipeline graph job item', () => {
};
const triggerActiveClass = 'gl-shadow-x0-y0-b3-s1-blue-500';
- const delayedJobFixture = getJSONFixture('jobs/delayed.json');
+
+ const delayedJob = {
+ __typename: 'CiJob',
+ name: 'delayed job',
+ scheduledAt: '2015-07-03T10:01:00.000Z',
+ needs: [],
+ status: {
+ __typename: 'DetailedStatus',
+ icon: 'status_scheduled',
+ tooltip: 'delayed manual action (%{remainingTime})',
+ hasDetails: true,
+ detailsPath: '/root/kinder-pipe/-/jobs/5339',
+ group: 'scheduled',
+ action: {
+ __typename: 'StatusAction',
+ icon: 'time-out',
+ title: 'Unschedule',
+ path: '/frontend-fixtures/builds-project/-/jobs/142/unschedule',
+ buttonTitle: 'Unschedule job',
+ },
+ },
+ };
+
const mockJob = {
id: 4256,
name: 'test',
@@ -24,8 +46,8 @@ describe('pipeline graph job item', () => {
label: 'passed',
tooltip: 'passed',
group: 'success',
- details_path: '/root/ci-mock/builds/4256',
- has_details: true,
+ detailsPath: '/root/ci-mock/builds/4256',
+ hasDetails: true,
action: {
icon: 'retry',
title: 'Retry',
@@ -42,8 +64,8 @@ describe('pipeline graph job item', () => {
text: 'passed',
label: 'passed',
group: 'success',
- details_path: '/root/ci-mock/builds/4257',
- has_details: false,
+ detailsPath: '/root/ci-mock/builds/4257',
+ hasDetails: false,
},
};
@@ -58,7 +80,7 @@ describe('pipeline graph job item', () => {
wrapper.vm.$nextTick(() => {
const link = wrapper.find('a');
- expect(link.attributes('href')).toBe(mockJob.status.details_path);
+ expect(link.attributes('href')).toBe(mockJob.status.detailsPath);
expect(link.attributes('title')).toBe(`${mockJob.name} - ${mockJob.status.label}`);
@@ -145,7 +167,7 @@ describe('pipeline graph job item', () => {
describe('for delayed job', () => {
it('displays remaining time in tooltip', () => {
createWrapper({
- job: delayedJobFixture,
+ job: delayedJob,
});
expect(findJobWithLink().attributes('title')).toBe(
diff --git a/spec/frontend/pipelines/graph/linked_pipeline_spec.js b/spec/frontend/pipelines/graph/linked_pipeline_spec.js
index c7d95526a0c..af5cd907dd8 100644
--- a/spec/frontend/pipelines/graph/linked_pipeline_spec.js
+++ b/spec/frontend/pipelines/graph/linked_pipeline_spec.js
@@ -4,11 +4,7 @@ import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { UPSTREAM, DOWNSTREAM } from '~/pipelines/components/graph/constants';
import LinkedPipelineComponent from '~/pipelines/components/graph/linked_pipeline.vue';
import CiStatus from '~/vue_shared/components/ci_icon.vue';
-import mockData from './linked_pipelines_mock_data';
-
-const mockPipeline = mockData.triggered[0];
-const validTriggeredPipelineId = mockPipeline.project.id;
-const invalidTriggeredPipelineId = mockPipeline.project.id + 5;
+import mockPipeline from './linked_pipelines_mock_data';
describe('Linked pipeline', () => {
let wrapper;
@@ -39,10 +35,10 @@ describe('Linked pipeline', () => {
describe('rendered output', () => {
const props = {
pipeline: mockPipeline,
- projectId: invalidTriggeredPipelineId,
columnTitle: 'Downstream',
type: DOWNSTREAM,
expanded: false,
+ isLoading: false,
};
beforeEach(() => {
@@ -60,7 +56,7 @@ describe('Linked pipeline', () => {
});
it('should render the pipeline status icon svg', () => {
- expect(wrapper.find('.ci-status-icon-failed svg').exists()).toBe(true);
+ expect(wrapper.find('.ci-status-icon-success svg').exists()).toBe(true);
});
it('should have a ci-status child component', () => {
@@ -73,8 +69,8 @@ describe('Linked pipeline', () => {
it('should correctly compute the tooltip text', () => {
expect(wrapper.vm.tooltipText).toContain(mockPipeline.project.name);
- expect(wrapper.vm.tooltipText).toContain(mockPipeline.details.status.label);
- expect(wrapper.vm.tooltipText).toContain(mockPipeline.source_job.name);
+ expect(wrapper.vm.tooltipText).toContain(mockPipeline.status.label);
+ expect(wrapper.vm.tooltipText).toContain(mockPipeline.sourceJob.name);
expect(wrapper.vm.tooltipText).toContain(mockPipeline.id);
});
@@ -82,11 +78,7 @@ describe('Linked pipeline', () => {
const titleAttr = findLinkedPipeline().attributes('title');
expect(titleAttr).toContain(mockPipeline.project.name);
- expect(titleAttr).toContain(mockPipeline.details.status.label);
- });
-
- it('sets the loading prop to false', () => {
- expect(findButton().props('loading')).toBe(false);
+ expect(titleAttr).toContain(mockPipeline.status.label);
});
it('should display multi-project label when pipeline project id is not the same as triggered pipeline project id', () => {
@@ -96,18 +88,20 @@ describe('Linked pipeline', () => {
describe('parent/child', () => {
const downstreamProps = {
- pipeline: mockPipeline,
- projectId: validTriggeredPipelineId,
+ pipeline: {
+ ...mockPipeline,
+ multiproject: false,
+ },
columnTitle: 'Downstream',
type: DOWNSTREAM,
expanded: false,
+ isLoading: false,
};
const upstreamProps = {
...downstreamProps,
columnTitle: 'Upstream',
type: UPSTREAM,
- expanded: false,
};
it('parent/child label container should exist', () => {
@@ -122,7 +116,7 @@ describe('Linked pipeline', () => {
it('should have the name of the trigger job on the card when it is a child pipeline', () => {
createWrapper(downstreamProps);
- expect(findDownstreamPipelineTitle().text()).toBe(mockPipeline.source_job.name);
+ expect(findDownstreamPipelineTitle().text()).toBe(mockPipeline.sourceJob.name);
});
it('should display parent label when pipeline project id is the same as triggered_by pipeline project id', () => {
@@ -132,12 +126,12 @@ describe('Linked pipeline', () => {
it('downstream pipeline should contain the correct link', () => {
createWrapper(downstreamProps);
- expect(findPipelineLink().attributes('href')).toBe(mockData.triggered_by.path);
+ expect(findPipelineLink().attributes('href')).toBe(downstreamProps.pipeline.path);
});
it('upstream pipeline should contain the correct link', () => {
createWrapper(upstreamProps);
- expect(findPipelineLink().attributes('href')).toBe(mockData.triggered_by.path);
+ expect(findPipelineLink().attributes('href')).toBe(upstreamProps.pipeline.path);
});
it.each`
@@ -183,11 +177,11 @@ describe('Linked pipeline', () => {
describe('when isLoading is true', () => {
const props = {
- pipeline: { ...mockPipeline, isLoading: true },
- projectId: invalidTriggeredPipelineId,
+ pipeline: mockPipeline,
columnTitle: 'Downstream',
type: DOWNSTREAM,
expanded: false,
+ isLoading: true,
};
beforeEach(() => {
@@ -202,10 +196,10 @@ describe('Linked pipeline', () => {
describe('on click/hover', () => {
const props = {
pipeline: mockPipeline,
- projectId: validTriggeredPipelineId,
columnTitle: 'Downstream',
type: DOWNSTREAM,
expanded: false,
+ isLoading: false,
};
beforeEach(() => {
@@ -228,7 +222,7 @@ describe('Linked pipeline', () => {
it('should emit downstreamHovered with job name on mouseover', () => {
findLinkedPipeline().trigger('mouseover');
- expect(wrapper.emitted().downstreamHovered).toStrictEqual([['trigger_job']]);
+ expect(wrapper.emitted().downstreamHovered).toStrictEqual([['test_c']]);
});
it('should emit downstreamHovered with empty string on mouseleave', () => {
@@ -238,7 +232,7 @@ describe('Linked pipeline', () => {
it('should emit pipelineExpanded with job name and expanded state on click', () => {
findExpandButton().trigger('click');
- expect(wrapper.emitted().pipelineExpandToggle).toStrictEqual([['trigger_job', true]]);
+ expect(wrapper.emitted().pipelineExpandToggle).toStrictEqual([['test_c', true]]);
});
});
});
diff --git a/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js b/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
index 24cc6e76098..2f03b846525 100644
--- a/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
+++ b/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
@@ -4,7 +4,6 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
import {
DOWNSTREAM,
- GRAPHQL,
UPSTREAM,
LAYER_VIEW,
STAGE_VIEW,
@@ -52,9 +51,6 @@ describe('Linked Pipelines Column', () => {
...defaultProps,
...props,
},
- provide: {
- dataMethod: GRAPHQL,
- },
});
};
diff --git a/spec/frontend/pipelines/graph/linked_pipelines_mock_data.js b/spec/frontend/pipelines/graph/linked_pipelines_mock_data.js
index eb05669463b..955b70cbd3b 100644
--- a/spec/frontend/pipelines/graph/linked_pipelines_mock_data.js
+++ b/spec/frontend/pipelines/graph/linked_pipelines_mock_data.js
@@ -1,3800 +1,22 @@
export default {
- id: 23211253,
- user: {
- id: 3585,
- name: 'Achilleas Pipinellis',
- username: 'axil',
- state: 'active',
- avatar_url: 'https://assets.gitlab-static.net/uploads/-/system/user/avatar/3585/avatar.png',
- web_url: 'https://gitlab.com/axil',
- status_tooltip_html:
- '\u003cspan class="user-status-emoji has-tooltip" title="I like pizza" data-html="true" data-placement="top"\u003e\u003cgl-emoji title="slice of pizza" data-name="pizza" data-unicode-version="6.0"\u003e🍕\u003c/gl-emoji\u003e\u003c/span\u003e',
- path: '/axil',
+ __typename: 'Pipeline',
+ id: 195,
+ iid: '5',
+ path: '/root/elemenohpee/-/pipelines/195',
+ status: {
+ __typename: 'DetailedStatus',
+ group: 'success',
+ label: 'passed',
+ icon: 'status_success',
},
- active: false,
- coverage: null,
- source: 'push',
- source_job: {
- name: 'trigger_job',
+ sourceJob: {
+ __typename: 'CiJob',
+ name: 'test_c',
},
- created_at: '2018-06-05T11:31:30.452Z',
- updated_at: '2018-10-31T16:35:31.305Z',
- path: '/gitlab-org/gitlab-runner/pipelines/23211253',
- flags: {
- latest: false,
- stuck: false,
- auto_devops: false,
- merge_request: false,
- yaml_errors: false,
- retryable: false,
- cancelable: false,
- failure_reason: false,
+ project: {
+ __typename: 'Project',
+ name: 'elemenohpee',
+ fullPath: 'root/elemenohpee',
},
- details: {
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-runner/pipelines/23211253',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- duration: 53,
- finished_at: '2018-10-31T16:35:31.299Z',
- stages: [
- {
- name: 'prebuild',
- title: 'prebuild: passed',
- groups: [
- {
- name: 'review-docs-deploy',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'manual play action',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-runner/-/jobs/72469032',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-org/gitlab-runner/-/jobs/72469032/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- jobs: [
- {
- id: 72469032,
- name: 'review-docs-deploy',
- started: '2018-10-31T16:34:58.778Z',
- archived: false,
- build_path: '/gitlab-org/gitlab-runner/-/jobs/72469032',
- retry_path: '/gitlab-org/gitlab-runner/-/jobs/72469032/retry',
- play_path: '/gitlab-org/gitlab-runner/-/jobs/72469032/play',
- playable: true,
- scheduled: false,
- created_at: '2018-06-05T11:31:30.495Z',
- updated_at: '2018-10-31T16:35:31.251Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'manual play action',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-runner/-/jobs/72469032',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-org/gitlab-runner/-/jobs/72469032/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-runner/pipelines/23211253#prebuild',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/gitlab-org/gitlab-runner/pipelines/23211253#prebuild',
- dropdown_path: '/gitlab-org/gitlab-runner/pipelines/23211253/stage.json?stage=prebuild',
- },
- {
- name: 'test',
- title: 'test: passed',
- groups: [
- {
- name: 'docs check links',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-runner/-/jobs/72469033',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-runner/-/jobs/72469033/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 72469033,
- name: 'docs check links',
- started: '2018-06-05T11:31:33.240Z',
- archived: false,
- build_path: '/gitlab-org/gitlab-runner/-/jobs/72469033',
- retry_path: '/gitlab-org/gitlab-runner/-/jobs/72469033/retry',
- playable: false,
- scheduled: false,
- created_at: '2018-06-05T11:31:30.627Z',
- updated_at: '2018-06-05T11:31:54.363Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-runner/-/jobs/72469033',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-runner/-/jobs/72469033/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-runner/pipelines/23211253#test',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/gitlab-org/gitlab-runner/pipelines/23211253#test',
- dropdown_path: '/gitlab-org/gitlab-runner/pipelines/23211253/stage.json?stage=test',
- },
- {
- name: 'cleanup',
- title: 'cleanup: skipped',
- groups: [
- {
- name: 'review-docs-cleanup',
- size: 1,
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual stop action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-org/gitlab-runner/-/jobs/72469034',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'stop',
- title: 'Stop',
- path: '/gitlab-org/gitlab-runner/-/jobs/72469034/play',
- method: 'post',
- button_title: 'Stop this environment',
- },
- },
- jobs: [
- {
- id: 72469034,
- name: 'review-docs-cleanup',
- started: null,
- archived: false,
- build_path: '/gitlab-org/gitlab-runner/-/jobs/72469034',
- play_path: '/gitlab-org/gitlab-runner/-/jobs/72469034/play',
- playable: true,
- scheduled: false,
- created_at: '2018-06-05T11:31:30.760Z',
- updated_at: '2018-06-05T11:31:56.037Z',
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual stop action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-org/gitlab-runner/-/jobs/72469034',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'stop',
- title: 'Stop',
- path: '/gitlab-org/gitlab-runner/-/jobs/72469034/play',
- method: 'post',
- button_title: 'Stop this environment',
- },
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-org/gitlab-runner/pipelines/23211253#cleanup',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- path: '/gitlab-org/gitlab-runner/pipelines/23211253#cleanup',
- dropdown_path: '/gitlab-org/gitlab-runner/pipelines/23211253/stage.json?stage=cleanup',
- },
- ],
- artifacts: [],
- manual_actions: [
- {
- name: 'review-docs-cleanup',
- path: '/gitlab-org/gitlab-runner/-/jobs/72469034/play',
- playable: true,
- scheduled: false,
- },
- {
- name: 'review-docs-deploy',
- path: '/gitlab-org/gitlab-runner/-/jobs/72469032/play',
- playable: true,
- scheduled: false,
- },
- ],
- scheduled_actions: [],
- },
- ref: {
- name: 'docs/add-development-guide-to-readme',
- path: '/gitlab-org/gitlab-runner/commits/docs/add-development-guide-to-readme',
- tag: false,
- branch: true,
- merge_request: false,
- },
- commit: {
- id: '8083eb0a920572214d0dccedd7981f05d535ad46',
- short_id: '8083eb0a',
- title: 'Add link to development guide in readme',
- created_at: '2018-06-05T11:30:48.000Z',
- parent_ids: ['1d7cf79b5a1a2121b9474ac20d61c1b8f621289d'],
- message:
- 'Add link to development guide in readme\n\nCloses https://gitlab.com/gitlab-org/gitlab-runner/issues/3122\n',
- author_name: 'Achilleas Pipinellis',
- author_email: 'axil@gitlab.com',
- authored_date: '2018-06-05T11:30:48.000Z',
- committer_name: 'Achilleas Pipinellis',
- committer_email: 'axil@gitlab.com',
- committed_date: '2018-06-05T11:30:48.000Z',
- author: {
- id: 3585,
- name: 'Achilleas Pipinellis',
- username: 'axil',
- state: 'active',
- avatar_url: 'https://assets.gitlab-static.net/uploads/-/system/user/avatar/3585/avatar.png',
- web_url: 'https://gitlab.com/axil',
- status_tooltip_html: null,
- path: '/axil',
- },
- author_gravatar_url:
- 'https://secure.gravatar.com/avatar/1d37af00eec153a8333a4ce18e9aea41?s=80\u0026d=identicon',
- commit_url:
- 'https://gitlab.com/gitlab-org/gitlab-runner/commit/8083eb0a920572214d0dccedd7981f05d535ad46',
- commit_path: '/gitlab-org/gitlab-runner/commit/8083eb0a920572214d0dccedd7981f05d535ad46',
- },
- project: { id: 20 },
- triggered_by: {
- id: 12,
- user: {
- id: 376774,
- name: 'Alessio Caiazza',
- username: 'nolith',
- state: 'active',
- avatar_url: 'https://assets.gitlab-static.net/uploads/-/system/user/avatar/376774/avatar.png',
- web_url: 'https://gitlab.com/nolith',
- status_tooltip_html: null,
- path: '/nolith',
- },
- active: false,
- coverage: null,
- source: 'pipeline',
- source_job: {
- name: 'trigger_job',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051',
- details: {
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- },
- duration: 118,
- finished_at: '2018-10-31T16:41:40.615Z',
- stages: [
- {
- name: 'build-images',
- title: 'build-images: skipped',
- groups: [
- {
- name: 'image:bootstrap',
- size: 1,
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982853',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- jobs: [
- {
- id: 11421321982853,
- name: 'image:bootstrap',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982853',
- play_path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- playable: true,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.704Z',
- updated_at: '2018-10-31T16:35:24.118Z',
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982853',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- },
- ],
- },
- {
- name: 'image:builder-onbuild',
- size: 1,
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982854',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- jobs: [
- {
- id: 1149822131854,
- name: 'image:builder-onbuild',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982854',
- play_path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- playable: true,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.728Z',
- updated_at: '2018-10-31T16:35:24.070Z',
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982854',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- },
- ],
- },
- {
- name: 'image:nginx-onbuild',
- size: 1,
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982855',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- jobs: [
- {
- id: 11498285523424,
- name: 'image:nginx-onbuild',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982855',
- play_path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- playable: true,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.753Z',
- updated_at: '2018-10-31T16:35:24.033Z',
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982855',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051#build-images',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051#build-images',
- dropdown_path: '/gitlab-com/gitlab-docs/pipelines/34993051/stage.json?stage=build-images',
- },
- {
- name: 'build',
- title: 'build: failed',
- groups: [
- {
- name: 'compile_dev',
- size: 1,
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed - (script failure)',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114984694',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/528/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 1149846949786,
- name: 'compile_dev',
- started: '2018-10-31T16:39:41.598Z',
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114984694',
- retry_path: '/gitlab-com/gitlab-docs/-/jobs/114984694/retry',
- playable: false,
- scheduled: false,
- created_at: '2018-10-31T16:39:41.138Z',
- updated_at: '2018-10-31T16:41:40.072Z',
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed - (script failure)',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114984694',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/528/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- recoverable: false,
- },
- ],
- },
- ],
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051#build',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051#build',
- dropdown_path: '/gitlab-com/gitlab-docs/pipelines/34993051/stage.json?stage=build',
- },
- {
- name: 'deploy',
- title: 'deploy: skipped',
- groups: [
- {
- name: 'review',
- size: 1,
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982857',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- jobs: [
- {
- id: 11498282342357,
- name: 'review',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982857',
- playable: false,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.805Z',
- updated_at: '2018-10-31T16:41:40.569Z',
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982857',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- },
- ],
- },
- {
- name: 'review_stop',
- size: 1,
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982858',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- jobs: [
- {
- id: 114982858,
- name: 'review_stop',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982858',
- playable: false,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.840Z',
- updated_at: '2018-10-31T16:41:40.480Z',
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982858',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051#deploy',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051#deploy',
- dropdown_path: '/gitlab-com/gitlab-docs/pipelines/34993051/stage.json?stage=deploy',
- },
- ],
- artifacts: [],
- manual_actions: [
- {
- name: 'image:bootstrap',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- playable: true,
- scheduled: false,
- },
- {
- name: 'image:builder-onbuild',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- playable: true,
- scheduled: false,
- },
- {
- name: 'image:nginx-onbuild',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- playable: true,
- scheduled: false,
- },
- {
- name: 'review_stop',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982858/play',
- playable: false,
- scheduled: false,
- },
- ],
- scheduled_actions: [],
- },
- project: {
- id: 20,
- name: 'Test',
- full_path: '/gitlab-com/gitlab-docs',
- full_name: 'GitLab.com / GitLab Docs',
- },
- triggered_by: {
- id: 349932310342451,
- user: {
- id: 376774,
- name: 'Alessio Caiazza',
- username: 'nolith',
- state: 'active',
- avatar_url:
- 'https://assets.gitlab-static.net/uploads/-/system/user/avatar/376774/avatar.png',
- web_url: 'https://gitlab.com/nolith',
- status_tooltip_html: null,
- path: '/nolith',
- },
- active: false,
- coverage: null,
- source: 'pipeline',
- source_job: {
- name: 'trigger_job',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051',
- details: {
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- },
- duration: 118,
- finished_at: '2018-10-31T16:41:40.615Z',
- stages: [
- {
- name: 'build-images',
- title: 'build-images: skipped',
- groups: [
- {
- name: 'image:bootstrap',
- size: 1,
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982853',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- jobs: [
- {
- id: 11421321982853,
- name: 'image:bootstrap',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982853',
- play_path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- playable: true,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.704Z',
- updated_at: '2018-10-31T16:35:24.118Z',
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982853',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- },
- ],
- },
- {
- name: 'image:builder-onbuild',
- size: 1,
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982854',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- jobs: [
- {
- id: 1149822131854,
- name: 'image:builder-onbuild',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982854',
- play_path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- playable: true,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.728Z',
- updated_at: '2018-10-31T16:35:24.070Z',
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982854',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- },
- ],
- },
- {
- name: 'image:nginx-onbuild',
- size: 1,
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982855',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- jobs: [
- {
- id: 11498285523424,
- name: 'image:nginx-onbuild',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982855',
- play_path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- playable: true,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.753Z',
- updated_at: '2018-10-31T16:35:24.033Z',
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982855',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051#build-images',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051#build-images',
- dropdown_path:
- '/gitlab-com/gitlab-docs/pipelines/34993051/stage.json?stage=build-images',
- },
- {
- name: 'build',
- title: 'build: failed',
- groups: [
- {
- name: 'compile_dev',
- size: 1,
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed - (script failure)',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114984694',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-com/gitlab-docs/-/jobs/114984694/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 1149846949786,
- name: 'compile_dev',
- started: '2018-10-31T16:39:41.598Z',
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114984694',
- retry_path: '/gitlab-com/gitlab-docs/-/jobs/114984694/retry',
- playable: false,
- scheduled: false,
- created_at: '2018-10-31T16:39:41.138Z',
- updated_at: '2018-10-31T16:41:40.072Z',
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed - (script failure)',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114984694',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-com/gitlab-docs/-/jobs/114984694/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- recoverable: false,
- },
- ],
- },
- ],
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051#build',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051#build',
- dropdown_path: '/gitlab-com/gitlab-docs/pipelines/34993051/stage.json?stage=build',
- },
- {
- name: 'deploy',
- title: 'deploy: skipped',
- groups: [
- {
- name: 'review',
- size: 1,
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982857',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- jobs: [
- {
- id: 11498282342357,
- name: 'review',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982857',
- playable: false,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.805Z',
- updated_at: '2018-10-31T16:41:40.569Z',
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982857',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- },
- ],
- },
- {
- name: 'review_stop',
- size: 1,
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982858',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- jobs: [
- {
- id: 114982858,
- name: 'review_stop',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982858',
- playable: false,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.840Z',
- updated_at: '2018-10-31T16:41:40.480Z',
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982858',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051#deploy',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051#deploy',
- dropdown_path: '/gitlab-com/gitlab-docs/pipelines/34993051/stage.json?stage=deploy',
- },
- ],
- artifacts: [],
- manual_actions: [
- {
- name: 'image:bootstrap',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- playable: true,
- scheduled: false,
- },
- {
- name: 'image:builder-onbuild',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- playable: true,
- scheduled: false,
- },
- {
- name: 'image:nginx-onbuild',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- playable: true,
- scheduled: false,
- },
- {
- name: 'review_stop',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982858/play',
- playable: false,
- scheduled: false,
- },
- ],
- scheduled_actions: [],
- },
- project: {
- id: 20,
- name: 'GitLab Docs',
- full_path: '/gitlab-com/gitlab-docs',
- full_name: 'GitLab.com / GitLab Docs',
- },
- },
- triggered: [],
- },
- triggered: [
- {
- id: 34993051,
- user: {
- id: 376774,
- name: 'Alessio Caiazza',
- username: 'nolith',
- state: 'active',
- avatar_url:
- 'https://assets.gitlab-static.net/uploads/-/system/user/avatar/376774/avatar.png',
- web_url: 'https://gitlab.com/nolith',
- status_tooltip_html: null,
- path: '/nolith',
- },
- active: false,
- coverage: null,
- source: 'pipeline',
- source_job: {
- name: 'trigger_job',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051',
- details: {
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- },
- duration: 118,
- finished_at: '2018-10-31T16:41:40.615Z',
- stages: [
- {
- name: 'build-images',
- title: 'build-images: skipped',
- groups: [
- {
- name: 'image:bootstrap',
- size: 1,
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982853',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- jobs: [
- {
- id: 114982853,
- name: 'image:bootstrap',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982853',
- play_path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- playable: true,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.704Z',
- updated_at: '2018-10-31T16:35:24.118Z',
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982853',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- },
- ],
- },
- {
- name: 'image:builder-onbuild',
- size: 1,
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982854',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- jobs: [
- {
- id: 114982854,
- name: 'image:builder-onbuild',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982854',
- play_path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- playable: true,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.728Z',
- updated_at: '2018-10-31T16:35:24.070Z',
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982854',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- },
- ],
- },
- {
- name: 'image:nginx-onbuild',
- size: 1,
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982855',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- jobs: [
- {
- id: 114982855,
- name: 'image:nginx-onbuild',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982855',
- play_path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- playable: true,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.753Z',
- updated_at: '2018-10-31T16:35:24.033Z',
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982855',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051#build-images',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051#build-images',
- dropdown_path:
- '/gitlab-com/gitlab-docs/pipelines/34993051/stage.json?stage=build-images',
- },
- {
- name: 'build',
- title: 'build: failed',
- groups: [
- {
- name: 'compile_dev',
- size: 1,
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed - (script failure)',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114984694',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/528/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 114984694,
- name: 'compile_dev',
- started: '2018-10-31T16:39:41.598Z',
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114984694',
- retry_path: '/gitlab-com/gitlab-docs/-/jobs/114984694/retry',
- playable: false,
- scheduled: false,
- created_at: '2018-10-31T16:39:41.138Z',
- updated_at: '2018-10-31T16:41:40.072Z',
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed - (script failure)',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114984694',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/528/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- recoverable: false,
- },
- ],
- },
- ],
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051#build',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051#build',
- dropdown_path: '/gitlab-com/gitlab-docs/pipelines/34993051/stage.json?stage=build',
- },
- {
- name: 'deploy',
- title: 'deploy: skipped',
- groups: [
- {
- name: 'review',
- size: 1,
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982857',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- jobs: [
- {
- id: 114982857,
- name: 'review',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982857',
- playable: false,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.805Z',
- updated_at: '2018-10-31T16:41:40.569Z',
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982857',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- },
- ],
- },
- {
- name: 'review_stop',
- size: 1,
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982858',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- jobs: [
- {
- id: 114982858,
- name: 'review_stop',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982858',
- playable: false,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.840Z',
- updated_at: '2018-10-31T16:41:40.480Z',
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982858',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051#deploy',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051#deploy',
- dropdown_path: '/gitlab-com/gitlab-docs/pipelines/34993051/stage.json?stage=deploy',
- },
- ],
- artifacts: [],
- manual_actions: [
- {
- name: 'image:bootstrap',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- playable: true,
- scheduled: false,
- },
- {
- name: 'image:builder-onbuild',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- playable: true,
- scheduled: false,
- },
- {
- name: 'image:nginx-onbuild',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- playable: true,
- scheduled: false,
- },
- {
- name: 'review_stop',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982858/play',
- playable: false,
- scheduled: false,
- },
- ],
- scheduled_actions: [],
- },
- project: {
- id: 20,
- name: 'GitLab Docs',
- full_path: '/gitlab-com/gitlab-docs',
- full_name: 'GitLab.com / GitLab Docs',
- },
- },
- {
- id: 34993052,
- user: {
- id: 376774,
- name: 'Alessio Caiazza',
- username: 'nolith',
- state: 'active',
- avatar_url:
- 'https://assets.gitlab-static.net/uploads/-/system/user/avatar/376774/avatar.png',
- web_url: 'https://gitlab.com/nolith',
- status_tooltip_html: null,
- path: '/nolith',
- },
- active: false,
- coverage: null,
- source: 'pipeline',
- source_job: {
- name: 'trigger_job',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051',
- details: {
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- },
- duration: 118,
- finished_at: '2018-10-31T16:41:40.615Z',
- stages: [
- {
- name: 'build-images',
- title: 'build-images: skipped',
- groups: [
- {
- name: 'image:bootstrap',
- size: 1,
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982853',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- jobs: [
- {
- id: 114982853,
- name: 'image:bootstrap',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982853',
- play_path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- playable: true,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.704Z',
- updated_at: '2018-10-31T16:35:24.118Z',
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982853',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- },
- ],
- },
- {
- name: 'image:builder-onbuild',
- size: 1,
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982854',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- jobs: [
- {
- id: 114982854,
- name: 'image:builder-onbuild',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982854',
- play_path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- playable: true,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.728Z',
- updated_at: '2018-10-31T16:35:24.070Z',
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982854',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- },
- ],
- },
- {
- name: 'image:nginx-onbuild',
- size: 1,
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982855',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- jobs: [
- {
- id: 1224982855,
- name: 'image:nginx-onbuild',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982855',
- play_path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- playable: true,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.753Z',
- updated_at: '2018-10-31T16:35:24.033Z',
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982855',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051#build-images',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051#build-images',
- dropdown_path:
- '/gitlab-com/gitlab-docs/pipelines/34993051/stage.json?stage=build-images',
- },
- {
- name: 'build',
- title: 'build: failed',
- groups: [
- {
- name: 'compile_dev',
- size: 1,
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed - (script failure)',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114984694',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-com/gitlab-docs/-/jobs/114984694/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 1123984694,
- name: 'compile_dev',
- started: '2018-10-31T16:39:41.598Z',
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114984694',
- retry_path: '/gitlab-com/gitlab-docs/-/jobs/114984694/retry',
- playable: false,
- scheduled: false,
- created_at: '2018-10-31T16:39:41.138Z',
- updated_at: '2018-10-31T16:41:40.072Z',
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed - (script failure)',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114984694',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-com/gitlab-docs/-/jobs/114984694/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- recoverable: false,
- },
- ],
- },
- ],
- status: {
- icon: 'status_failed',
- text: 'failed',
- label: 'failed',
- group: 'failed',
- tooltip: 'failed',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051#build',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051#build',
- dropdown_path: '/gitlab-com/gitlab-docs/pipelines/34993051/stage.json?stage=build',
- },
- {
- name: 'deploy',
- title: 'deploy: skipped',
- groups: [
- {
- name: 'review',
- size: 1,
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982857',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- jobs: [
- {
- id: 1143232982857,
- name: 'review',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982857',
- playable: false,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.805Z',
- updated_at: '2018-10-31T16:41:40.569Z',
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982857',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- },
- ],
- },
- {
- name: 'review_stop',
- size: 1,
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982858',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- jobs: [
- {
- id: 114921313182858,
- name: 'review_stop',
- started: null,
- archived: false,
- build_path: '/gitlab-com/gitlab-docs/-/jobs/114982858',
- playable: false,
- scheduled: false,
- created_at: '2018-10-31T16:35:23.840Z',
- updated_at: '2018-10-31T16:41:40.480Z',
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/-/jobs/114982858',
- illustration: {
- image:
- 'https://assets.gitlab-static.net/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/gitlab-com/gitlab-docs/pipelines/34993051#deploy',
- illustration: null,
- favicon:
- 'https://gitlab.com/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- path: '/gitlab-com/gitlab-docs/pipelines/34993051#deploy',
- dropdown_path: '/gitlab-com/gitlab-docs/pipelines/34993051/stage.json?stage=deploy',
- },
- ],
- artifacts: [],
- manual_actions: [
- {
- name: 'image:bootstrap',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982853/play',
- playable: true,
- scheduled: false,
- },
- {
- name: 'image:builder-onbuild',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982854/play',
- playable: true,
- scheduled: false,
- },
- {
- name: 'image:nginx-onbuild',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982855/play',
- playable: true,
- scheduled: false,
- },
- {
- name: 'review_stop',
- path: '/gitlab-com/gitlab-docs/-/jobs/114982858/play',
- playable: false,
- scheduled: false,
- },
- ],
- scheduled_actions: [],
- },
- project: {
- id: 20,
- name: 'GitLab Docs',
- full_path: '/gitlab-com/gitlab-docs',
- full_name: 'GitLab.com / GitLab Docs',
- },
- triggered: [
- {
- id: 26,
- user: null,
- active: false,
- coverage: null,
- source: 'push',
- source_job: {
- name: 'trigger_job',
- },
- created_at: '2019-01-06T17:48:37.599Z',
- updated_at: '2019-01-06T17:48:38.371Z',
- path: '/h5bp/html5-boilerplate/pipelines/26',
- flags: {
- latest: true,
- stuck: false,
- auto_devops: false,
- merge_request: false,
- yaml_errors: false,
- retryable: true,
- cancelable: false,
- failure_reason: false,
- },
- details: {
- status: {
- icon: 'status_warning',
- text: 'passed',
- label: 'passed with warnings',
- group: 'success-with-warnings',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/pipelines/26',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- duration: null,
- finished_at: '2019-01-06T17:48:38.370Z',
- stages: [
- {
- name: 'build',
- title: 'build: passed',
- groups: [
- {
- name: 'build:linux',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/526',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/526/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 526,
- name: 'build:linux',
- started: '2019-01-06T08:48:20.236Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/526',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/526/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:37.806Z',
- updated_at: '2019-01-06T17:48:37.806Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/526',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/526/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- ],
- },
- {
- name: 'build:osx',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/527',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/527/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 527,
- name: 'build:osx',
- started: '2019-01-06T07:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/527',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/527/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:37.846Z',
- updated_at: '2019-01-06T17:48:37.846Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/527',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/527/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/pipelines/26#build',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/h5bp/html5-boilerplate/pipelines/26#build',
- dropdown_path: '/h5bp/html5-boilerplate/pipelines/26/stage.json?stage=build',
- },
- {
- name: 'test',
- title: 'test: passed with warnings',
- groups: [
- {
- name: 'jenkins',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: null,
- group: 'success',
- tooltip: null,
- has_details: false,
- details_path: null,
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- jobs: [
- {
- id: 546,
- name: 'jenkins',
- started: '2019-01-06T11:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/546',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:38.359Z',
- updated_at: '2019-01-06T17:48:38.359Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: null,
- group: 'success',
- tooltip: null,
- has_details: false,
- details_path: null,
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- },
- ],
- },
- {
- name: 'rspec:linux',
- size: 3,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: false,
- details_path: null,
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- jobs: [
- {
- id: 528,
- name: 'rspec:linux 0 3',
- started: '2019-01-06T09:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/528',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/528/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:37.885Z',
- updated_at: '2019-01-06T17:48:37.885Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/528',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/528/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- {
- id: 529,
- name: 'rspec:linux 1 3',
- started: '2019-01-06T09:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/529',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/529/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:37.907Z',
- updated_at: '2019-01-06T17:48:37.907Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/529',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/529/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- {
- id: 530,
- name: 'rspec:linux 2 3',
- started: '2019-01-06T09:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/530',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/530/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:37.927Z',
- updated_at: '2019-01-06T17:48:37.927Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/530',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/530/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- ],
- },
- {
- name: 'rspec:osx',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/535',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/535/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 535,
- name: 'rspec:osx',
- started: '2019-01-06T09:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/535',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/535/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:38.018Z',
- updated_at: '2019-01-06T17:48:38.018Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/535',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/535/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- ],
- },
- {
- name: 'rspec:windows',
- size: 3,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: false,
- details_path: null,
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- jobs: [
- {
- id: 531,
- name: 'rspec:windows 0 3',
- started: '2019-01-06T09:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/531',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/531/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:37.944Z',
- updated_at: '2019-01-06T17:48:37.944Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/531',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/531/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- {
- id: 532,
- name: 'rspec:windows 1 3',
- started: '2019-01-06T09:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/532',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/532/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:37.962Z',
- updated_at: '2019-01-06T17:48:37.962Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/532',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/532/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- {
- id: 534,
- name: 'rspec:windows 2 3',
- started: '2019-01-06T09:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/534',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/534/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:37.999Z',
- updated_at: '2019-01-06T17:48:37.999Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/534',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/534/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- ],
- },
- {
- name: 'spinach:linux',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/536',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/536/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 536,
- name: 'spinach:linux',
- started: '2019-01-06T09:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/536',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/536/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:38.050Z',
- updated_at: '2019-01-06T17:48:38.050Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/536',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/536/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- ],
- },
- {
- name: 'spinach:osx',
- size: 1,
- status: {
- icon: 'status_warning',
- text: 'failed',
- label: 'failed (allowed to fail)',
- group: 'failed-with-warnings',
- tooltip: 'failed - (unknown failure) (allowed to fail)',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/537',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/537/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 537,
- name: 'spinach:osx',
- started: '2019-01-06T09:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/537',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/537/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:38.069Z',
- updated_at: '2019-01-06T17:48:38.069Z',
- status: {
- icon: 'status_warning',
- text: 'failed',
- label: 'failed (allowed to fail)',
- group: 'failed-with-warnings',
- tooltip: 'failed - (unknown failure) (allowed to fail)',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/537',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/537/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- callout_message: 'There is an unknown failure, please try again',
- recoverable: true,
- },
- ],
- },
- ],
- status: {
- icon: 'status_warning',
- text: 'passed',
- label: 'passed with warnings',
- group: 'success-with-warnings',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/pipelines/26#test',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/h5bp/html5-boilerplate/pipelines/26#test',
- dropdown_path: '/h5bp/html5-boilerplate/pipelines/26/stage.json?stage=test',
- },
- {
- name: 'security',
- title: 'security: passed',
- groups: [
- {
- name: 'container_scanning',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/541',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/541/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 541,
- name: 'container_scanning',
- started: '2019-01-06T09:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/541',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/541/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:38.186Z',
- updated_at: '2019-01-06T17:48:38.186Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/541',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/541/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- ],
- },
- {
- name: 'dast',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/538',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/538/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 538,
- name: 'dast',
- started: '2019-01-06T09:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/538',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/538/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:38.087Z',
- updated_at: '2019-01-06T17:48:38.087Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/538',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/538/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- ],
- },
- {
- name: 'dependency_scanning',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/540',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/540/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 540,
- name: 'dependency_scanning',
- started: '2019-01-06T09:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/540',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/540/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:38.153Z',
- updated_at: '2019-01-06T17:48:38.153Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/540',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/540/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- ],
- },
- {
- name: 'sast',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/539',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/539/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 539,
- name: 'sast',
- started: '2019-01-06T09:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/539',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/539/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:38.121Z',
- updated_at: '2019-01-06T17:48:38.121Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/539',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/539/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/pipelines/26#security',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/h5bp/html5-boilerplate/pipelines/26#security',
- dropdown_path: '/h5bp/html5-boilerplate/pipelines/26/stage.json?stage=security',
- },
- {
- name: 'deploy',
- title: 'deploy: passed',
- groups: [
- {
- name: 'production',
- size: 1,
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/544',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- jobs: [
- {
- id: 544,
- name: 'production',
- started: null,
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/544',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:38.313Z',
- updated_at: '2019-01-06T17:48:38.313Z',
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/544',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- },
- ],
- },
- {
- name: 'staging',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/542',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/542/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- jobs: [
- {
- id: 542,
- name: 'staging',
- started: '2019-01-06T11:48:20.237Z',
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/542',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/542/retry',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:38.219Z',
- updated_at: '2019-01-06T17:48:38.219Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/542',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/h5bp/html5-boilerplate/-/jobs/542/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- },
- ],
- },
- {
- name: 'stop staging',
- size: 1,
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/543',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- jobs: [
- {
- id: 543,
- name: 'stop staging',
- started: null,
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/543',
- playable: false,
- scheduled: false,
- created_at: '2019-01-06T17:48:38.283Z',
- updated_at: '2019-01-06T17:48:38.283Z',
- status: {
- icon: 'status_skipped',
- text: 'skipped',
- label: 'skipped',
- group: 'skipped',
- tooltip: 'skipped',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/543',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-8b877955fbf175e42ae65b6cb95346e15282c6fc5b682756c329af3a0055225e.svg',
- size: 'svg-430',
- title: 'This job has been skipped',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_skipped-0b9c5e543588945e8c4ca57786bbf2d0c56631959c9f853300392d0315be829b.png',
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/pipelines/26#deploy',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/h5bp/html5-boilerplate/pipelines/26#deploy',
- dropdown_path: '/h5bp/html5-boilerplate/pipelines/26/stage.json?stage=deploy',
- },
- {
- name: 'notify',
- title: 'notify: passed',
- groups: [
- {
- name: 'slack',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'manual play action',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/545',
- illustration: {
- image:
- '/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/h5bp/html5-boilerplate/-/jobs/545/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- jobs: [
- {
- id: 545,
- name: 'slack',
- started: null,
- archived: false,
- build_path: '/h5bp/html5-boilerplate/-/jobs/545',
- retry_path: '/h5bp/html5-boilerplate/-/jobs/545/retry',
- play_path: '/h5bp/html5-boilerplate/-/jobs/545/play',
- playable: true,
- scheduled: false,
- created_at: '2019-01-06T17:48:38.341Z',
- updated_at: '2019-01-06T17:48:38.341Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'manual play action',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/-/jobs/545',
- illustration: {
- image:
- '/assets/illustrations/manual_action-2b4ca0d1bcfd92aebf33d484e36cbf7a102d007f76b5a0cfea636033a629d601.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/h5bp/html5-boilerplate/-/jobs/545/play',
- method: 'post',
- button_title: 'Trigger this manual action',
- },
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/h5bp/html5-boilerplate/pipelines/26#notify',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/h5bp/html5-boilerplate/pipelines/26#notify',
- dropdown_path: '/h5bp/html5-boilerplate/pipelines/26/stage.json?stage=notify',
- },
- ],
- artifacts: [
- {
- name: 'build:linux',
- expired: null,
- expire_at: null,
- path: '/h5bp/html5-boilerplate/-/jobs/526/artifacts/download',
- browse_path: '/h5bp/html5-boilerplate/-/jobs/526/artifacts/browse',
- },
- {
- name: 'build:osx',
- expired: null,
- expire_at: null,
- path: '/h5bp/html5-boilerplate/-/jobs/527/artifacts/download',
- browse_path: '/h5bp/html5-boilerplate/-/jobs/527/artifacts/browse',
- },
- ],
- manual_actions: [
- {
- name: 'stop staging',
- path: '/h5bp/html5-boilerplate/-/jobs/543/play',
- playable: false,
- scheduled: false,
- },
- {
- name: 'production',
- path: '/h5bp/html5-boilerplate/-/jobs/544/play',
- playable: false,
- scheduled: false,
- },
- {
- name: 'slack',
- path: '/h5bp/html5-boilerplate/-/jobs/545/play',
- playable: true,
- scheduled: false,
- },
- ],
- scheduled_actions: [],
- },
- ref: {
- name: 'main',
- path: '/h5bp/html5-boilerplate/commits/main',
- tag: false,
- branch: true,
- merge_request: false,
- },
- commit: {
- id: 'bad98c453eab56d20057f3929989251d45cd1a8b',
- short_id: 'bad98c45',
- title: 'remove instances of shrink-to-fit=no (#2103)',
- created_at: '2018-12-17T20:52:18.000Z',
- parent_ids: ['49130f6cfe9ff1f749015d735649a2bc6f66cf3a'],
- message:
- 'remove instances of shrink-to-fit=no (#2103)\n\ncloses #2102\r\n\r\nPer my findings, the need for it as a default was rectified with the release of iOS 9.3, where the viewport no longer shrunk to accommodate overflow, as was introduced in iOS 9.',
- author_name: "Scott O'Hara",
- author_email: 'scottaohara@users.noreply.github.com',
- authored_date: '2018-12-17T20:52:18.000Z',
- committer_name: 'Rob Larsen',
- committer_email: 'rob@drunkenfist.com',
- committed_date: '2018-12-17T20:52:18.000Z',
- author: null,
- author_gravatar_url:
- 'https://www.gravatar.com/avatar/6d597df7cf998d16cbe00ccac063b31e?s=80\u0026d=identicon',
- commit_url:
- 'http://localhost:3001/h5bp/html5-boilerplate/commit/bad98c453eab56d20057f3929989251d45cd1a8b',
- commit_path: '/h5bp/html5-boilerplate/commit/bad98c453eab56d20057f3929989251d45cd1a8b',
- },
- retry_path: '/h5bp/html5-boilerplate/pipelines/26/retry',
- triggered_by: {
- id: 4,
- user: null,
- active: false,
- coverage: null,
- source: 'push',
- source_job: {
- name: 'trigger_job',
- },
- path: '/gitlab-org/gitlab-test/pipelines/4',
- details: {
- status: {
- icon: 'status_warning',
- text: 'passed',
- label: 'passed with warnings',
- group: 'success-with-warnings',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-test/pipelines/4',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- },
- project: {
- id: 1,
- name: 'Gitlab Test',
- full_path: '/gitlab-org/gitlab-test',
- full_name: 'Gitlab Org / Gitlab Test',
- },
- },
- triggered: [],
- project: {
- id: 20,
- name: 'GitLab Docs',
- full_path: '/gitlab-com/gitlab-docs',
- full_name: 'GitLab.com / GitLab Docs',
- },
- },
- ],
- },
- ],
+ multiproject: true,
};
diff --git a/spec/graphql/resolvers/users/groups_resolver_spec.rb b/spec/graphql/resolvers/users/groups_resolver_spec.rb
new file mode 100644
index 00000000000..0fdb6da5ae9
--- /dev/null
+++ b/spec/graphql/resolvers/users/groups_resolver_spec.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Users::GroupsResolver do
+ include GraphqlHelpers
+ include AdminModeHelper
+
+ describe '#resolve' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:guest_group) { create(:group, name: 'public guest', path: 'public-guest') }
+ let_it_be(:private_maintainer_group) { create(:group, :private, name: 'b private maintainer', path: 'b-private-maintainer') }
+ let_it_be(:public_developer_group) { create(:group, project_creation_level: nil, name: 'c public developer', path: 'c-public-developer') }
+ let_it_be(:public_maintainer_group) { create(:group, name: 'a public maintainer', path: 'a-public-maintainer') }
+
+ subject(:resolved_items) { resolve_groups(args: group_arguments, current_user: current_user, obj: resolver_object) }
+
+ let(:group_arguments) { {} }
+ let(:current_user) { user }
+ let(:resolver_object) { user }
+
+ before_all do
+ guest_group.add_guest(user)
+ private_maintainer_group.add_maintainer(user)
+ public_developer_group.add_developer(user)
+ public_maintainer_group.add_maintainer(user)
+ end
+
+ context 'when paginatable_namespace_drop_down_for_project_creation feature flag is disabled' do
+ before do
+ stub_feature_flags(paginatable_namespace_drop_down_for_project_creation: false)
+ end
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'when resolver object is current user' do
+ context 'when permission is :create_projects' do
+ let(:group_arguments) { { permission_scope: :create_projects } }
+
+ specify do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ private_maintainer_group,
+ public_developer_group
+ ]
+ )
+ end
+ end
+
+ specify do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ private_maintainer_group,
+ public_developer_group,
+ guest_group
+ ]
+ )
+ end
+
+ context 'when search is provided' do
+ let(:group_arguments) { { search: 'maintainer' } }
+
+ specify do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ private_maintainer_group
+ ]
+ )
+ end
+ end
+ end
+
+ context 'when resolver object is different from current user' do
+ let(:current_user) { create(:user) }
+
+ it { is_expected.to be_nil }
+
+ context 'when current_user is admin' do
+ let(:current_user) { create(:user, :admin) }
+
+ before do
+ enable_admin_mode!(current_user)
+ end
+
+ specify do
+ is_expected.to match(
+ [
+ public_maintainer_group,
+ private_maintainer_group,
+ public_developer_group,
+ guest_group
+ ]
+ )
+ end
+ end
+ end
+ end
+
+ def resolve_groups(args:, current_user:, obj:)
+ resolve(described_class, args: args, ctx: { current_user: current_user }, obj: obj)&.items
+ end
+end
diff --git a/spec/graphql/types/merge_requests/reviewer_type_spec.rb b/spec/graphql/types/merge_requests/reviewer_type_spec.rb
index 4ede8e5788f..4d357a922f8 100644
--- a/spec/graphql/types/merge_requests/reviewer_type_spec.rb
+++ b/spec/graphql/types/merge_requests/reviewer_type_spec.rb
@@ -33,6 +33,7 @@ RSpec.describe GitlabSchema.types['MergeRequestReviewer'] do
merge_request_interaction
namespace
timelogs
+ groups
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/user_type_spec.rb b/spec/graphql/types/user_type_spec.rb
index 363ccdf88b7..0bad8c95ba2 100644
--- a/spec/graphql/types/user_type_spec.rb
+++ b/spec/graphql/types/user_type_spec.rb
@@ -38,6 +38,7 @@ RSpec.describe GitlabSchema.types['User'] do
callouts
namespace
timelogs
+ groups
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index 9cf3808ab72..4cb795b4eab 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -284,7 +284,7 @@ RSpec.describe IssuesHelper do
iid: issue.iid,
is_issue_author: 'false',
issue_type: 'issue',
- new_issue_path: new_project_issue_path(project),
+ new_issue_path: new_project_issue_path(project, { issue: { description: "Related to \##{issue.iid}.\n\n" } }),
project_path: project.full_path,
report_abuse_path: new_abuse_report_path(user_id: issue.author.id, ref_url: issue_url(issue)),
submit_as_spam_path: mark_as_spam_project_issue_path(project, issue)
diff --git a/spec/models/preloaders/user_max_access_level_in_groups_preloader_spec.rb b/spec/models/preloaders/user_max_access_level_in_groups_preloader_spec.rb
new file mode 100644
index 00000000000..8144e1ad233
--- /dev/null
+++ b/spec/models/preloaders/user_max_access_level_in_groups_preloader_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Preloaders::UserMaxAccessLevelInGroupsPreloader do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group1) { create(:group, :private).tap { |g| g.add_developer(user) } }
+ let_it_be(:group2) { create(:group, :private).tap { |g| g.add_developer(user) } }
+ let_it_be(:group3) { create(:group, :private) }
+
+ let(:max_query_regex) { /SELECT MAX\("members"\."access_level"\).+/ }
+ let(:groups) { [group1, group2, group3] }
+
+ shared_examples 'executes N max member permission queries to the DB' do
+ it 'executes the specified max membership queries' do
+ queries = ActiveRecord::QueryRecorder.new do
+ groups.each { |group| user.can?(:read_group, group) }
+ end
+
+ max_queries = queries.log.grep(max_query_regex)
+
+ expect(max_queries.count).to eq(expected_query_count)
+ end
+ end
+
+ context 'when the preloader is used', :request_store do
+ before do
+ described_class.new(groups, user).execute
+ end
+
+ it_behaves_like 'executes N max member permission queries to the DB' do
+ # Will query all groups where the user is not already a member
+ let(:expected_query_count) { 1 }
+ end
+
+ context 'when user has access but is not a direct member of the group' do
+ let(:groups) { [group1, group2, group3, create(:group, :private, parent: group1)] }
+
+ it_behaves_like 'executes N max member permission queries to the DB' do
+ # One query for group with no access and another one where the user is not a direct member
+ let(:expected_query_count) { 2 }
+ end
+ end
+ end
+
+ context 'when the preloader is not used', :request_store do
+ it_behaves_like 'executes N max member permission queries to the DB' do
+ let(:expected_query_count) { groups.count }
+ end
+ end
+end
diff --git a/spec/policies/user_policy_spec.rb b/spec/policies/user_policy_spec.rb
index 78212f06526..b800e7dbc43 100644
--- a/spec/policies/user_policy_spec.rb
+++ b/spec/policies/user_policy_spec.rb
@@ -3,8 +3,12 @@
require 'spec_helper'
RSpec.describe UserPolicy do
- let(:current_user) { create(:user) }
- let(:user) { create(:user) }
+ let_it_be(:admin) { create(:user, :admin) }
+ let_it_be(:regular_user) { create(:user) }
+ let_it_be(:subject_user) { create(:user) }
+
+ let(:current_user) { regular_user }
+ let(:user) { subject_user }
subject { described_class.new(current_user, user) }
@@ -16,7 +20,7 @@ RSpec.describe UserPolicy do
let(:token) { create(:personal_access_token, user: user) }
context 'when user is admin' do
- let(:current_user) { create(:user, :admin) }
+ let(:current_user) { admin }
context 'when admin mode is enabled', :enable_admin_mode do
it { is_expected.to be_allowed(:read_user_personal_access_tokens) }
@@ -42,7 +46,7 @@ RSpec.describe UserPolicy do
describe "creating a different user's Personal Access Tokens" do
context 'when current_user is admin' do
- let(:current_user) { create(:user, :admin) }
+ let(:current_user) { admin }
context 'when admin mode is enabled and current_user is not blocked', :enable_admin_mode do
it { is_expected.to be_allowed(:create_user_personal_access_token) }
@@ -92,7 +96,7 @@ RSpec.describe UserPolicy do
end
context "when an admin user tries to destroy a regular user" do
- let(:current_user) { create(:user, :admin) }
+ let(:current_user) { admin }
context 'when admin mode is enabled', :enable_admin_mode do
it { is_expected.to be_allowed(ability) }
@@ -104,7 +108,7 @@ RSpec.describe UserPolicy do
end
context "when an admin user tries to destroy a ghost user" do
- let(:current_user) { create(:user, :admin) }
+ let(:current_user) { admin }
let(:user) { create(:user, :ghost) }
it { is_expected.not_to be_allowed(ability) }
@@ -132,7 +136,7 @@ RSpec.describe UserPolicy do
context 'disabling the two-factor authentication of another user' do
context 'when the executor is an admin', :enable_admin_mode do
- let(:current_user) { create(:user, :admin) }
+ let(:current_user) { admin }
it { is_expected.to be_allowed(:disable_two_factor) }
end
@@ -145,7 +149,7 @@ RSpec.describe UserPolicy do
describe "reading a user's group count" do
context "when current_user is an admin", :enable_admin_mode do
- let(:current_user) { create(:user, :admin) }
+ let(:current_user) { admin }
it { is_expected.to be_allowed(:read_group_count) }
end
@@ -172,4 +176,30 @@ RSpec.describe UserPolicy do
it { is_expected.to be_allowed(:read_user_profile) }
end
end
+
+ describe ':read_user_groups' do
+ context 'when user is admin' do
+ let(:current_user) { admin }
+
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed(:read_user_groups) }
+ end
+
+ context 'when admin mode is disabled' do
+ it { is_expected.not_to be_allowed(:read_user_groups) }
+ end
+ end
+
+ context 'when user is not an admin' do
+ context 'requesting their own manageable groups' do
+ subject { described_class.new(current_user, current_user) }
+
+ it { is_expected.to be_allowed(:read_user_groups) }
+ end
+
+ context "requesting a different user's manageable groups" do
+ it { is_expected.not_to be_allowed(:read_user_groups) }
+ end
+ end
+ end
end
diff --git a/spec/requests/api/graphql/current_user/groups_query_spec.rb b/spec/requests/api/graphql/current_user/groups_query_spec.rb
new file mode 100644
index 00000000000..39f323b21a3
--- /dev/null
+++ b/spec/requests/api/graphql/current_user/groups_query_spec.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Query current user groups' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:guest_group) { create(:group, name: 'public guest', path: 'public-guest') }
+ let_it_be(:private_maintainer_group) { create(:group, :private, name: 'b private maintainer', path: 'b-private-maintainer') }
+ let_it_be(:public_developer_group) { create(:group, :private, project_creation_level: nil, name: 'c public developer', path: 'c-public-developer') }
+ let_it_be(:public_maintainer_group) { create(:group, :private, name: 'a public maintainer', path: 'a-public-maintainer') }
+
+ let(:group_arguments) { {} }
+ let(:current_user) { user }
+
+ let(:fields) do
+ <<~GRAPHQL
+ nodes { id path fullPath name }
+ GRAPHQL
+ end
+
+ let(:query) do
+ graphql_query_for('currentUser', {}, query_graphql_field('groups', group_arguments, fields))
+ end
+
+ before_all do
+ guest_group.add_guest(user)
+ private_maintainer_group.add_maintainer(user)
+ public_developer_group.add_developer(user)
+ public_maintainer_group.add_maintainer(user)
+ end
+
+ subject { graphql_data.dig('currentUser', 'groups', 'nodes') }
+
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'avoids N+1 queries', :request_store do
+ control = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) }
+
+ new_group = create(:group, :private)
+ new_group.add_maintainer(current_user)
+
+ expect { post_graphql(query, current_user: current_user) }.not_to exceed_query_limit(control)
+ end
+
+ it 'returns all groups where the user is a direct member' do
+ is_expected.to match(
+ expected_group_hash(
+ public_maintainer_group,
+ private_maintainer_group,
+ public_developer_group,
+ guest_group
+ )
+ )
+ end
+
+ context 'when permission_scope is CREATE_PROJECTS' do
+ let(:group_arguments) { { permission_scope: :CREATE_PROJECTS } }
+
+ specify do
+ is_expected.to match(
+ expected_group_hash(
+ public_maintainer_group,
+ private_maintainer_group,
+ public_developer_group
+ )
+ )
+ end
+
+ context 'when search is provided' do
+ let(:group_arguments) { { permission_scope: :CREATE_PROJECTS, search: 'maintainer' } }
+
+ specify do
+ is_expected.to match(
+ expected_group_hash(
+ public_maintainer_group,
+ private_maintainer_group
+ )
+ )
+ end
+ end
+ end
+
+ context 'when search is provided' do
+ let(:group_arguments) { { search: 'maintainer' } }
+
+ specify do
+ is_expected.to match(
+ expected_group_hash(
+ public_maintainer_group,
+ private_maintainer_group
+ )
+ )
+ end
+ end
+
+ def expected_group_hash(*groups)
+ groups.map do |group|
+ {
+ 'id' => group.to_global_id.to_s,
+ 'name' => group.name,
+ 'path' => group.path,
+ 'fullPath' => group.full_path
+ }
+ end
+ end
+end