diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-24 00:11:23 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-24 00:11:23 +0300 |
commit | 0510f42da38bb0eb1d06aeb82b4d16ed71135776 (patch) | |
tree | b83ce9d25ff8bf1938c44e51916fd5bd86e5ee8b | |
parent | 5e9fe672fa0eda6322bd392e8502d1886804bd07 (diff) |
Add latest changes from gitlab-org/gitlab@master
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 |