Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-07-28 18:10:23 +00:00
parent 1d9f78b3a4
commit a66948df0c
49 changed files with 768 additions and 215 deletions

View File

@ -31,6 +31,30 @@
"alternate": "ee/lib/{}.rb",
"type": "test"
},
"app/assets/javascripts/*.js": {
"alternate": "spec/frontend/{}_spec.js",
"type": "source"
},
"app/assets/javascripts/*.vue": {
"alternate": "spec/frontend/{}_spec.js",
"type": "source"
},
"spec/frontend/*_spec.js": {
"alternate": ["app/assets/javascripts/{}.vue", "app/assets/javascripts/{}.js"],
"type": "test"
},
"ee/app/assets/javascripts/*.js": {
"alternate": "ee/spec/frontend/{}_spec.js",
"type": "source"
},
"ee/app/assets/javascripts/*.vue": {
"alternate": "ee/spec/frontend/{}_spec.js",
"type": "source"
},
"ee/spec/frontend/*_spec.js": {
"alternate": ["ee/app/assets/javascripts/{}.vue", "ee/app/assets/javascripts/{}.js"],
"type": "test"
},
"*.rb": {"dispatch": "bundle exec rubocop {file}"},
"*_spec.rb": {"dispatch": "bundle exec rspec {file}"}
}

View File

@ -5,9 +5,12 @@ import initSortDiscussions from './sort_discussions';
import { store } from './stores';
import initTimelineToggle from './timeline';
const el = document.getElementById('js-vue-notes');
export default () => {
const el = document.getElementById('js-vue-notes');
if (!el) {
return;
}
if (el) {
// eslint-disable-next-line no-new
new Vue({
el,
@ -59,4 +62,4 @@ if (el) {
initDiscussionFilters(store);
initSortDiscussions(store);
initTimelineToggle(store);
}
};

View File

@ -23,10 +23,10 @@ import { s__, __ } from '~/locale';
// import DependencyRow from '~/packages/details/components/dependency_row.vue';
// import InstallationCommands from '~/packages/details/components/installation_commands.vue';
// import PackageFiles from '~/packages/details/components/package_files.vue';
// import PackageHistory from '~/packages/details/components/package_history.vue';
// import PackageListRow from '~/packages/shared/components/package_list_row.vue';
import PackagesListLoader from '~/packages/shared/components/packages_list_loader.vue';
import { packageTypeToTrackCategory } from '~/packages/shared/utils';
import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
import {
PACKAGE_TYPE_NUGET,
PACKAGE_TYPE_COMPOSER,
@ -60,7 +60,7 @@ export default {
PackagesListLoader,
// PackageListRow,
// DependencyRow,
// PackageHistory,
PackageHistory,
// AdditionalMetadata,
// InstallationCommands,
// PackageFiles,
@ -124,10 +124,10 @@ export default {
return this.packageEntity.packageFiles;
},
isLoading() {
return this.$apollo.queries.package;
return this.$apollo.queries.packageEntity.loading;
},
isValidPackage() {
return Boolean(this.packageEntity?.name);
return this.isLoading || Boolean(this.packageEntity?.name);
},
tracking() {
return {
@ -237,10 +237,10 @@ export default {
<gl-tabs>
<gl-tab :title="__('Detail')">
<div data-qa-selector="package_information_content">
<!-- <package-history :package-entity="packageEntity" :project-name="projectName" />
<div v-if="!isLoading" data-qa-selector="package_information_content">
<package-history :package-entity="packageEntity" :project-name="projectName" />
<installation-commands
<!-- <installation-commands
:package-entity="packageEntity"
:npm-path="npmPath"
:npm-help-path="npmHelpPath"

View File

@ -1,6 +1,7 @@
<script>
import { GlLink, GlSprintf } from '@gitlab/ui';
import { first } from 'lodash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { truncateSha } from '~/lib/utils/text_utility';
import { s__, n__ } from '~/locale';
import { HISTORY_PIPELINES_LIMIT } from '~/packages/details/constants';
@ -45,7 +46,7 @@ export default {
},
computed: {
pipelines() {
return this.packageEntity.pipelines || [];
return this.packageEntity?.pipelines?.nodes || [];
},
firstPipeline() {
return first(this.pipelines);
@ -71,6 +72,9 @@ export default {
truncate(value) {
return truncateSha(value);
},
convertToBaseId(value) {
return getIdFromGraphQLId(value);
},
},
};
</script>
@ -88,7 +92,7 @@ export default {
<strong>{{ packageEntity.version }}</strong>
</template>
<template #datetime>
<time-ago-tooltip :time="packageEntity.created_at" />
<time-ago-tooltip :time="packageEntity.createdAt" />
</template>
</gl-sprintf>
</history-item>
@ -98,9 +102,7 @@ export default {
<history-item icon="commit" data-testid="first-pipeline-commit">
<gl-sprintf :message="$options.i18n.createdByCommitText">
<template #link>
<gl-link :href="firstPipeline.project.commit_url"
>#{{ truncate(firstPipeline.sha) }}</gl-link
>
<gl-link :href="firstPipeline.commitPath">#{{ truncate(firstPipeline.sha) }}</gl-link>
</template>
<template #branch>
<strong>{{ firstPipeline.ref }}</strong>
@ -110,10 +112,10 @@ export default {
<history-item icon="pipeline" data-testid="first-pipeline-pipeline">
<gl-sprintf :message="$options.i18n.createdByPipelineText">
<template #link>
<gl-link :href="firstPipeline.project.pipeline_url">#{{ firstPipeline.id }}</gl-link>
<gl-link :href="firstPipeline.path">#{{ convertToBaseId(firstPipeline.id) }}</gl-link>
</template>
<template #datetime>
<time-ago-tooltip :time="firstPipeline.created_at" />
<time-ago-tooltip :time="firstPipeline.createdAt" />
</template>
<template #author>{{ firstPipeline.user.name }}</template>
</gl-sprintf>
@ -127,7 +129,7 @@ export default {
<strong>{{ projectName }}</strong>
</template>
<template #datetime>
<time-ago-tooltip :time="packageEntity.created_at" />
<time-ago-tooltip :time="packageEntity.createdAt" />
</template>
</gl-sprintf>
</history-item>
@ -149,16 +151,16 @@ export default {
>
<gl-sprintf :message="$options.i18n.combinedUpdateText">
<template #link>
<gl-link :href="pipeline.project.commit_url">#{{ truncate(pipeline.sha) }}</gl-link>
<gl-link :href="pipeline.commitPath">#{{ truncate(pipeline.sha) }}</gl-link>
</template>
<template #branch>
<strong>{{ pipeline.ref }}</strong>
</template>
<template #pipeline>
<gl-link :href="pipeline.project.pipeline_url">#{{ pipeline.id }}</gl-link>
<gl-link :href="pipeline.path">#{{ convertToBaseId(pipeline.id) }}</gl-link>
</template>
<template #datetime>
<time-ago-tooltip :time="pipeline.created_at" />
<time-ago-tooltip :time="pipeline.createdAt" />
</template>
</gl-sprintf>
</history-item>

View File

@ -15,13 +15,22 @@ query getPackageDetails($id: ID!) {
}
pipelines(first: 3) {
nodes {
ref
id
sha
createdAt
commitPath
path
user {
name
}
project {
name
webUrl
}
}
}
packageFiles(first: 1000) {
packageFiles(first: 100) {
nodes {
id
fileMd5

View File

@ -3,10 +3,10 @@ import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
import initIssuableSidebar from '~/init_issuable_sidebar';
import { IssuableType } from '~/issuable_show/constants';
import Issue from '~/issue';
import '~/notes/index';
import initIncidentApp from '~/issue_show/incident';
import { initIssuableApp, initIssueHeaderActions } from '~/issue_show/issue';
import { parseIssuableData } from '~/issue_show/utils/parse_data';
import initNotesApp from '~/notes/index';
import { store } from '~/notes/stores';
import initRelatedMergeRequestsApp from '~/related_merge_requests';
import initSentryErrorStackTraceApp from '~/sentry_error_stack_trace';
@ -14,6 +14,8 @@ import initIssuableHeaderWarning from '~/vue_shared/components/issuable/init_iss
import ZenMode from '~/zen_mode';
export default function initShowIssue() {
initNotesApp();
const initialDataEl = document.getElementById('js-issuable-app');
const { issueType, ...issuableData } = parseIssuableData(initialDataEl);

View File

@ -22,6 +22,13 @@ class JiraConnect::SubscriptionsController < JiraConnect::ApplicationController
def index
@subscriptions = current_jira_installation.subscriptions.preload_namespace_route
respond_to do |format|
format.html
format.json do
render json: JiraConnect::AppDataSerializer.new(@subscriptions, !!current_user).as_json
end
end
end
def create

View File

@ -8,6 +8,7 @@ class Projects::ServicesController < Projects::ApplicationController
before_action :authorize_admin_project!
before_action :ensure_service_enabled
before_action :integration
before_action :default_integration, only: [:edit, :update]
before_action :web_hook_logs, only: [:edit, :update]
before_action :set_deprecation_notice_for_prometheus_integration, only: [:edit, :update]
before_action :redirect_deprecated_prometheus_integration, only: [:update]
@ -19,14 +20,22 @@ class Projects::ServicesController < Projects::ApplicationController
feature_category :integrations
def edit
@default_integration = Integration.default_integration(service.type, project)
end
def update
@integration.attributes = integration_params[:integration]
@integration.inherit_from_id = nil if integration_params[:integration][:inherit_from_id].blank?
attributes = integration_params[:integration]
saved = @integration.save(context: :manual_change)
if use_inherited_settings?(attributes)
@integration.inherit_from_id = default_integration.id
if saved = @integration.save(context: :manual_change)
BulkUpdateIntegrationService.new(default_integration, [@integration]).execute
end
else
attributes[:inherit_from_id] = nil
@integration.attributes = attributes
saved = @integration.save(context: :manual_change)
end
respond_to do |format|
format.html do
@ -88,6 +97,10 @@ class Projects::ServicesController < Projects::ApplicationController
end
alias_method :service, :integration
def default_integration
@default_integration ||= Integration.default_integration(integration.type, project)
end
def web_hook_logs
return unless integration.service_hook.present?
@ -115,4 +128,8 @@ class Projects::ServicesController < Projects::ApplicationController
message = s_('PrometheusService|You can now manage your Prometheus settings on the %{operations_link_start}Operations%{operations_link_end} page. Fields on this page have been deprecated.') % { operations_link_start: operations_link_start, operations_link_end: "</a>" }
flash.now[:alert] = message.html_safe
end
def use_inherited_settings?(attributes)
default_integration && attributes[:inherit_from_id] == default_integration.id.to_s
end
end

View File

@ -19,6 +19,11 @@ module Types
argument :release_tag, GraphQL::Types::String,
required: false,
description: 'Filter by release tag.'
argument :types, [Types::IssueTypeEnum],
as: :issue_types,
description: 'Filter by the given issue types.',
required: false
end
end
end

View File

@ -31,4 +31,9 @@ module TimeZoneHelper
}.slice(*attrs)
end
end
def local_time(timezone)
time_zone_instance = ActiveSupport::TimeZone.new(timezone) || Time.zone
time_zone_instance.now.strftime("%-l:%M %p")
end
end

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
class JiraConnect::AppDataSerializer
include Gitlab::Routing
include ::API::Helpers::RelatedResourcesHelpers
def initialize(subscriptions, signed_in)
@subscriptions = subscriptions
@signed_in = signed_in
end
def as_json
skip_groups = @subscriptions.map(&:namespace_id)
{
groups_path: api_v4_groups_path(params: { min_access_level: Gitlab::Access::MAINTAINER, skip_groups: skip_groups }),
subscriptions: JiraConnect::SubscriptionEntity.represent(@subscriptions).as_json,
subscriptions_path: jira_connect_subscriptions_path,
login_path: signed_in? ? nil : jira_connect_users_path
}
end
private
def signed_in?
!!@signed_in
end
end

View File

@ -0,0 +1,8 @@
# frozen_string_literal: true
class JiraConnect::GroupEntity < Grape::Entity
expose :name
expose :avatar_url
expose :full_name
expose :description
end

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
class JiraConnect::SubscriptionEntity < Grape::Entity
include Gitlab::Routing
expose :created_at
expose :unlink_path do |subscription|
jira_connect_subscription_path(subscription)
end
expose :namespace, with: JiraConnect::GroupEntity, as: :group
end

View File

@ -42,7 +42,7 @@ module Boards
end
def set_issue_types
params[:issue_types] = Issue::TYPES_FOR_LIST
params[:issue_types] ||= Issue::TYPES_FOR_LIST
end
def item_model

View File

@ -9,10 +9,10 @@ class BulkUpdateIntegrationService
# rubocop: disable CodeReuse/ActiveRecord
def execute
Integration.transaction do
Integration.where(id: batch.select(:id)).update_all(integration_hash)
Integration.where(id: batch_ids).update_all(integration_hash)
if integration.data_fields_present?
integration.data_fields.class.where(service_id: batch.select(:id)).update_all(data_fields_hash)
integration.data_fields.class.where(service_id: batch_ids).update_all(data_fields_hash)
end
end
end
@ -29,4 +29,13 @@ class BulkUpdateIntegrationService
def data_fields_hash
integration.to_data_fields_hash
end
def batch_ids
@batch_ids ||=
if batch.is_a?(ActiveRecord::Relation)
batch.select(:id)
else
batch.map(&:id)
end
end
end

View File

@ -73,6 +73,10 @@
= sprite_icon('location', css_class: 'fgray')
%span{ itemprop: 'addressLocality' }
= @user.location
.profile-link-holder.middle-dot-divider-sm.d-block.d-sm-inline.mb-1.mb-sm-0
= sprite_icon('clock', css_class: 'fgray')
%span
= local_time(@user.timezone)
- unless work_information(@user).blank?
.profile-link-holder.middle-dot-divider-sm.d-block.d-sm-inline
= sprite_icon('work', css_class: 'fgray')

View File

@ -11,13 +11,12 @@ class ScheduleDeleteOrphanedDeployments < ActiveRecord::Migration[6.1]
disable_ddl_transaction!
def up
queue_background_migration_jobs_by_range_at_intervals(
define_batchable_model('deployments'),
MIGRATION,
DELAY_INTERVAL,
batch_size: BATCH_SIZE,
track_jobs: true
)
# no-op.
# This background migration is rescheduled in 20210722010101_cleanup_delete_orphaned_deployments_background_migration.rb
# with a smaller batch size, because the initial attempt caused
# 80 failures out of 1639 batches (faiulre rate is 4.88%) due to statement timeouts,
# that takes approx. 1 hour to perform a cleanup/sync migration.
# See https://gitlab.com/gitlab-org/gitlab/-/issues/335071#note_618380503 for more information.
end
def down

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
class RescheduleDeleteOrphanedDeployments < ActiveRecord::Migration[6.1]
include Gitlab::Database::MigrationHelpers
MIGRATION = 'DeleteOrphanedDeployments'
BATCH_SIZE = 10_000
DELAY_INTERVAL = 2.minutes
disable_ddl_transaction!
def up
Gitlab::BackgroundMigration.steal(MIGRATION)
Gitlab::Database::BackgroundMigrationJob.for_migration_class(MIGRATION).delete_all
queue_background_migration_jobs_by_range_at_intervals(
define_batchable_model('deployments'),
MIGRATION,
DELAY_INTERVAL,
batch_size: BATCH_SIZE,
track_jobs: true
)
end
def down
# no-op
end
end

View File

@ -0,0 +1 @@
bbd39849499d16f92a5129506a87a6b253f209200bcb3a63c2432862c4b78aae

View File

@ -44,15 +44,17 @@ gitlab-ctl restart
## Changing time zone per user
To allow users to change the time zone in their profile, the feature flag `user_time_settings` should be enabled:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/57654) in GitLab 11.11, disabled by default behind `user_time_settings` [feature flag](feature_flags.md).
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/29669) in GitLab 13.9.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/29669) in GitLab 14.1.
1. [Start a Rails console session](operations/rails_console.md).
1. Enable the feature flag:
This setting controls the local time displayed on a user's profile.
See [&280](https://gitlab.com/groups/gitlab-org/-/epics/280) for other planned features.
```ruby
Feature.enable(:user_time_settings)
```
NOTE:
If a user has not set their time zone, it defaults to the time zone [configured at the instance level](#changing-your-time-zone). On GitLab.com, the default time zone is UTC.
1. You should now be able to see the timezone dropdown in the users' **Settings > Profile** page.
1. Navigate to [your user settings](../user/profile/index.md#access-your-user-settings).
1. Select your time zone from the dropdown.
![User Time Zone Settings](img/time_zone_settings.png)
![User Time Zone Settings](img/time_zone_settings.png)

View File

@ -16584,6 +16584,7 @@ Field that are available while modifying the custom mapping attributes for an HT
| <a id="boardissueinputnot"></a>`not` | [`NegatedBoardIssueInput`](#negatedboardissueinput) | List of negated arguments. |
| <a id="boardissueinputreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="boardissueinputsearch"></a>`search` | [`String`](#string) | Search query for issue title or description. |
| <a id="boardissueinputtypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter by the given issue types. |
| <a id="boardissueinputweight"></a>`weight` | [`String`](#string) | Filter by weight. |
| <a id="boardissueinputweightwildcardid"></a>`weightWildcardId` | [`WeightWildcardId`](#weightwildcardid) | Filter by weight ID wildcard. Incompatible with weight. |
@ -16736,6 +16737,7 @@ Represents an escalation rule.
| <a id="negatedboardissueinputmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Filter by milestone title. |
| <a id="negatedboardissueinputmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by reaction emoji applied by the current user. |
| <a id="negatedboardissueinputreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="negatedboardissueinputtypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter by the given issue types. |
| <a id="negatedboardissueinputweight"></a>`weight` | [`String`](#string) | Filter by weight. |
### `NegatedEpicBoardIssueInput`

View File

@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: howto
---
# Cloud deployment
# Cloud deployment **(FREE)**
Interacting with a major cloud provider may have become a much needed task that's
part of your delivery process. With GitLab you can

View File

@ -4,7 +4,7 @@ group: Release
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# Deployment safety
# Deployment safety **(FREE)**
Deployment jobs can be more sensitive than other jobs in a pipeline,
and might need to be treated with extra care. GitLab has several features

View File

@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: concepts, howto
---
# Incremental Rollouts with GitLab CI/CD
# Incremental rollouts with GitLab CI/CD **(FREE)**
When rolling out changes to your application, it is possible to release production changes
to only a portion of your Kubernetes pods as a risk mitigation strategy. By releasing
@ -37,8 +37,6 @@ use as examples to build your own:
## Manual Rollouts
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5415) in GitLab 10.8.
It is possible to configure GitLab to do incremental rollouts manually through `.gitlab-ci.yml`. Manual configuration
allows more control over the this feature. The steps in an incremental rollout depend on the
number of pods that are defined for the deployment, which are configured when the Kubernetes
@ -77,8 +75,6 @@ available, demonstrating manually triggered incremental rollouts.
## Timed Rollouts
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7545) in GitLab 11.4.
Timed rollouts behave in the same way as manual rollouts, except that each job is defined with a
delay in minutes before it deploys. Clicking the job reveals the countdown.

View File

@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: tutorial
---
# Authenticating and Reading Secrets With HashiCorp Vault
# Authenticating and reading secrets with HashiCorp Vault **(PREMIUM)**
This tutorial demonstrates how to authenticate, configure, and read secrets with HashiCorp's Vault from GitLab CI/CD.

View File

@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: tutorial
---
# Running Composer and npm scripts with deployment via SCP in GitLab CI/CD
# Running Composer and npm scripts with deployment via SCP in GitLab CI/CD **(FREE)**
This guide covers the building of dependencies of a PHP project while compiling assets via an npm script using [GitLab CI/CD](../../README.md).

View File

@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: tutorial
---
# Using Dpl as deployment tool
# Using Dpl as a deployment tool **(FREE)**
[Dpl](https://github.com/travis-ci/dpl) (pronounced like the letters D-P-L) is a deploy tool made for
continuous deployment that's developed and used by Travis CI, but can also be
@ -105,18 +105,18 @@ production:
We created two deploy jobs that are executed on different events:
1. `staging` is executed for all commits that were pushed to `master` branch,
1. `production` is executed for all pushed tags.
- `staging`: Executed for all commits pushed to the `master` branch
- `production`: Executed for all pushed tags
We also use two secure variables:
1. `HEROKU_STAGING_API_KEY` - Heroku API key used to deploy staging app,
1. `HEROKU_PRODUCTION_API_KEY` - Heroku API key used to deploy production app.
- `HEROKU_STAGING_API_KEY`: Heroku API key used to deploy staging app
- `HEROKU_PRODUCTION_API_KEY`: Heroku API key used to deploy production app
## Storing API keys
To add secure variables, navigate to your project's
**Settings > CI/CD > Variables**. The variables that are defined
**Settings > CI/CD > Variables**. The variables defined
in the project settings are sent along with the build script to the runner.
The secure variables are stored out of the repository. Never store secrets in
your project's `.gitlab-ci.yml`. It is also important that the secret's value
@ -125,7 +125,7 @@ is hidden in the job log.
You access added variable by prefixing it's name with `$` (on non-Windows runners)
or `%` (for Windows Batch runners):
1. `$VARIABLE` - use it for non-Windows runners
1. `%VARIABLE%` - use it for Windows Batch runners
- `$VARIABLE`: Use for non-Windows runners
- `%VARIABLE%`: Use for Windows Batch runners
Read more about the [CI/CD variables](../../variables/index.md).

View File

@ -5,19 +5,14 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: reference
---
# Review Apps
# Review Apps **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/21971) in GitLab 8.12. Further additions were made in GitLab 8.13 and 8.14.
> - Inspired by [Heroku's Review Apps](https://devcenter.heroku.com/articles/github-integration-review-apps), which itself was inspired by [Fourchette](https://github.com/rainforestapp/fourchette).
Review Apps is a collaboration tool that takes the hard work out of providing an environment to showcase product changes.
Review Apps is a collaboration tool that assists with providing an environment to showcase product changes.
NOTE:
If you have a Kubernetes cluster, you can automate this feature in your applications
by using [Auto DevOps](../../topics/autodevops/index.md).
## Introduction
Review Apps:
- Provide an automatic live preview of changes made in a feature branch by spinning up a dynamic environment for your merge requests.
@ -27,7 +22,7 @@ Review Apps:
![Review Apps Workflow](img/continuous-delivery-review-apps.svg)
In the above example:
In the previous example:
- A Review App is built every time a commit is pushed to `topic branch`.
- The reviewer fails two reviews before passing the third review.
@ -107,8 +102,6 @@ Other examples of Review Apps:
## Route Maps
> Introduced in GitLab 8.17. In GitLab 11.5, the file links are available in the merge request widget.
Route Maps allows you to go directly from source files
to public pages on the [environment](../environments/index.md) defined for
Review Apps.

View File

@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: concepts, howto
---
# Using external secrets in CI
# Using external secrets in CI **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218746) in GitLab 13.4 and GitLab Runner 13.4.
> - `file` setting [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/250695) in GitLab 14.1 and GitLab Runner 14.1.

View File

@ -34,9 +34,14 @@ any of the following Service Ping files:
#### The merge request **author** should
- Decide whether a Product Intelligence review is needed.
- Decide whether a Product Intelligence review is needed. You can skip the Product Intelligence
review and remove the labels if the changes are not related to the Product Intelligence domain and
are regular backend changes.
- If a Product Intelligence review is needed, add the labels
`~product intelligence` and `~product intelligence::review pending`.
- For merge requests authored by Product Intelligence team members:
- Assign both the `~backend` and `~product intelligence` reviews to another Product Intelligence team member.
- Assign the maintainer review to someone outside of the Product Intelligence group.
- Assign an
[engineer](https://gitlab.com/groups/gitlab-org/growth/product-intelligence/engineers/-/group_members?with_inherited_permissions=exclude) from the Product Intelligence team for a review.
- Set the correct attributes in the metric's YAML definition:

View File

@ -10,25 +10,24 @@ type: reference
GitLab Inc. periodically collects information about your instance in order
to perform various actions.
All statistics are opt-out. To enable or disable them:
All usage statistics are [opt-out](#enable-or-disable-usage-statistics).
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > Metrics and profiling**, and expand **Usage statistics**.
1. Enable or disable **Version check** and **Service ping**.
1. Select **Save changes**.
## Service Ping **(FREE SELF)**
## Network configuration
Service Ping is a process that collects and sends a weekly payload to GitLab Inc.
For more information, see the [Service Ping guide](../../../development/service_ping/index.md).
Allow network traffic from your GitLab instance to IP address `104.196.17.203:443`, to send
usage statistics to GitLab Inc.
### Instance-level analytics availability
If your GitLab instance is behind a proxy, set the appropriate [proxy configuration variables](https://docs.gitlab.com/omnibus/settings/environment-variables.html).
When Service Ping is enabled, GitLab gathers data from other instances and
enables certain [instance-level analytics features](../analytics/index.md)
that are dependent on Service Ping.
## Version Check **(FREE SELF)**
## Version check **(FREE SELF)**
If enabled, version check informs you if a new version is available and the
importance of it through a status. This is shown on the help page (i.e. `/help`)
for all signed in users, and on the admin pages. The statuses are:
importance of it through a status. The status displays on the help pages (`/help`)
for all signed-in users, and on the Admin Area pages. The statuses are:
- Green: You are running the latest version of GitLab.
- Orange: An updated version of GitLab is available.
@ -44,17 +43,12 @@ This information is used, among other things, to identify to which versions
patches must be backported, making sure active GitLab instances remain
secure.
If you disable version check, this information isn't collected. To enable or disable it:
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > Metrics and profiling**, and expand **Usage statistics**.
1. Enable or disable **Version check**.
1. Select **Save changes**.
If you [disable version check](#enable-or-disable-usage-statistics), this information isn't collected.
### Request flow example
The following example shows a basic request/response flow between the self-managed GitLab instance
and the GitLab Version Application:
The following example shows a basic request/response flow between a
self-managed GitLab instance and the GitLab Version Application:
```mermaid
sequenceDiagram
@ -67,14 +61,22 @@ sequenceDiagram
Version Application->>GitLab instance: Response (PNG/SVG)
```
## Service Ping **(FREE SELF)**
## Configure your network
See [Service Ping guide](../../../development/service_ping/index.md).
To send usage statistics to GitLab Inc., you must allow network traffic from your
GitLab instance to the IP address `104.196.17.203:443`.
## Instance-level analytics availability
If your GitLab instance is behind a proxy, set the appropriate
[proxy configuration variables](https://docs.gitlab.com/omnibus/settings/environment-variables.html).
After Service Ping is enabled, GitLab gathers data from other instances and
enables certain [instance-level analytics features](../analytics/index.md) that are dependent on Service Ping.
## Enable or disable usage statistics
To enable or disable Service Ping and version check:
1. On the top bar, select **Menu >** **{admin}** **Admin**.
1. In the left sidebar, select **Settings > Metrics and profiling**, and expand **Usage statistics**.
1. Select or clear the **Version check** and **Service ping** checkboxes.
1. Select **Save changes**.
<!-- ## Troubleshooting

View File

@ -589,30 +589,6 @@ by the application as correctly authenticated.
Authentication supports single form logins, multi-step login forms, and authenticating to URLs outside of the configured target URL.
Variables that are related to authenticated scans are:
```yaml
include:
- template: DAST.gitlab-ci.yml
dast:
variables:
DAST_WEBSITE: "https://example.com"
DAST_AUTH_URL: "https://login.example.com/"
DAST_BROWSER_PATH_TO_LOGIN_FORM: "css:.navigation-menu,css:.login-menu-item" # optional list of selectors that should be clicked on prior to attempting to input username/password into the sign-in HTML form
DAST_USERNAME: "admin"
DAST_PASSWORD: "P@55w0rd!"
DAST_USERNAME_FIELD: "name:username" # a selector describing the element containing the username field at the sign-in HTML form
DAST_PASSWORD_FIELD: "id:password" # a selector describing the element containing the password field at the sign-in HTML form
DAST_FIRST_SUBMIT_FIELD: "css:button[type='user-submit']" # optional, the selector of the element that when clicked will submit the username form of a multi-page login process
DAST_SUBMIT_FIELD: "css:button[type='submit']" # the selector of the element that when clicked will submit the login form or the password form of a multi-page login process
DAST_EXCLUDE_URLS: "http://example.com/sign-out" # optional, URLs to skip during the authenticated scan; comma-separated, no spaces in between
DAST_AUTH_VERIFICATION_URL: "http://example.com/loggedin_page" # optional, used to verify authentication is successful by expecting this URL once the login form has been submitted
DAST_AUTH_VERIFICATION_SELECTOR: "css:.user-profile" # optional, used to verify authentication is successful by expecting a selector to be present on the page once the login form has been submitted
DAST_AUTH_VERIFICATION_LOGIN_FORM: "true" # optional, used to verify authentication is successful by ensuring there are no login forms on the page once the login form has been submitted
DAST_AUTH_REPORT: "true" # optionally output an authentication debug report
```
WARNING:
**NEVER** run an authenticated scan against a production server. When an authenticated
scan is run, it may perform *any* function that the authenticated user can. This
@ -768,55 +744,56 @@ dast:
### Available CI/CD variables
You can use CI/CD variables to customize DAST.
These CI/CD variables are specific to DAST. They can be used to customize the behavior of DAST to your requirements.
| CI/CD variable | Type | Description |
|:------------------------------------------------|:--------------|:-------------------------------|
| `SECURE_ANALYZERS_PREFIX` | URL | Set the Docker registry base address from which to download the analyzer. |
| `DAST_WEBSITE` <sup>1</sup> | URL | The URL of the website to scan. `DAST_API_OPENAPI` must be specified if this is omitted. |
| `DAST_API_OPENAPI` | URL or string | The API specification to import. The specification can be hosted at a URL, or the name of a file present in the `/zap/wrk` directory. `DAST_WEBSITE` must be specified if this is omitted. |
| `DAST_API_SPECIFICATION` <sup>1</sup> | URL or string | [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/290241) in GitLab 13.12 and replaced by `DAST_API_OPENAPI`. To be removed in GitLab 15.0. The API specification to import. The specification can be hosted at a URL, or the name of a file present in the `/zap/wrk` directory. `DAST_WEBSITE` must be specified if this is omitted. |
| `DAST_SPIDER_START_AT_HOST` | boolean | Set to `false` to prevent DAST from resetting the target to its host before scanning. When `true`, non-host targets `http://test.site/some_path` is reset to `http://test.site` before scan. Default: `true`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258805) in GitLab 13.6. |
| `DAST_AUTH_URL` <sup>1</sup> | URL | The URL of the page containing the sign-in HTML form on the target website. `DAST_USERNAME` and `DAST_PASSWORD` are submitted with the login form to create an authenticated scan. Not supported for API scans. |
| `DAST_BROWSER_PATH_TO_LOGIN_FORM` <sup>1</sup> | selector | Comma-separated list of selectors that will be clicked on prior to attempting to enter `DAST_USERNAME` and `DAST_PASSWORD` into the login form. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/326633) in GitLab 14.1. |
| `DAST_USERNAME` <sup>1</sup> | string | The username to authenticate to in the website. |
| `DAST_PASSWORD` <sup>1</sup> | string | The password to authenticate to in the website. |
| `DAST_USERNAME_FIELD` <sup>1</sup> | string | The name of username field at the sign-in HTML form. |
| `DAST_PASSWORD_FIELD` <sup>1</sup> | string | The name of password field at the sign-in HTML form. |
| `DAST_SKIP_TARGET_CHECK` | boolean | Set to `true` to prevent DAST from checking that the target is available before scanning. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229067) in GitLab 13.8. |
| `DAST_MASK_HTTP_HEADERS` | string | Comma-separated list of request and response headers to be masked (GitLab 13.1). Must contain **all** headers to be masked. Refer to [list of headers that are masked by default](#hide-sensitive-information). |
| `DAST_EXCLUDE_URLS` <sup>1</sup> | URLs | The URLs to skip during the authenticated scan; comma-separated. Regular expression syntax can be used to match multiple URLs. For example, `.*` matches an arbitrary character sequence. Not supported for API scans. |
| `DAST_FULL_SCAN_ENABLED` <sup>1</sup> | boolean | Set to `true` to run a [ZAP Full Scan](https://www.zaproxy.org/docs/docker/full-scan/) instead of a [ZAP Baseline Scan](https://www.zaproxy.org/docs/docker/baseline-scan/). Default: `false` |
| `DAST_FULL_SCAN_DOMAIN_VALIDATION_REQUIRED` | boolean | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/293595)** in GitLab 14.0. Set to `true` to require domain validation when running DAST full scans. Not supported for API scans. Default: `false` |
| `DAST_AUTO_UPDATE_ADDONS` | boolean | ZAP add-ons are pinned to specific versions in the DAST Docker image. Set to `true` to download the latest versions when the scan starts. Default: `false` |
| `DAST_API_HOST_OVERRIDE` <sup>1</sup> | string | Used to override domains defined in API specification files. Only supported when importing the API specification from a URL. Example: `example.com:8080` |
| `DAST_EXCLUDE_RULES` | string | Set to a comma-separated list of Vulnerability Rule IDs to exclude them from running during the scan. Rule IDs are numbers and can be found from the DAST log or on the [ZAP project](https://www.zaproxy.org/docs/alerts/). For example, `HTTP Parameter Override` has a rule ID of `10026`. Cannot be used when `DAST_ONLY_INCLUDE_RULES` is set. **Note:** In earlier versions of GitLab the excluded rules were executed but vulnerabilities they generated were suppressed. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118641) in GitLab 12.10. |
| `DAST_ONLY_INCLUDE_RULES` | string | Set to a comma-separated list of Vulnerability Rule IDs to configure the scan to run only them. Rule IDs are numbers and can be found from the DAST log or on the [ZAP project](https://www.zaproxy.org/docs/alerts/). Cannot be used when `DAST_EXCLUDE_RULES` is set. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/250651) in GitLab 13.12. |
| `DAST_REQUEST_HEADERS` <sup>1</sup> | string | Set to a comma-separated list of request header names and values. Headers are added to every request made by DAST. For example, `Cache-control: no-cache,User-Agent: DAST/1.0` |
| `DAST_DEBUG` <sup>1</sup> | boolean | Enable debug message output. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_TARGET_AVAILABILITY_TIMEOUT` <sup>1</sup> | number | Time limit in seconds to wait for target availability. |
| `DAST_SPIDER_MINS` <sup>1</sup> | number | The maximum duration of the spider scan in minutes. Set to `0` for unlimited. Default: One minute, or unlimited when the scan is a full scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_HTML_REPORT` | string | The filename of the HTML report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_MARKDOWN_REPORT` | string | The filename of the Markdown report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_XML_REPORT` | string | The filename of the XML report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_INCLUDE_ALPHA_VULNERABILITIES` | boolean | Set to `true` to include alpha passive and active scan rules. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_USE_AJAX_SPIDER` <sup>1</sup> | boolean | Set to `true` to use the AJAX spider in addition to the traditional spider, useful for crawling sites that require JavaScript. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_PATHS` | string | Set to a comma-separated list of URLs for DAST to scan. For example, `/page1.html,/category1/page3.html,/page2.html`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214120) in GitLab 13.4. |
| `DAST_PATHS_FILE` | string | The file path containing the paths within `DAST_WEBSITE` to scan. The file must be plain text with one path per line. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258825) in GitLab 13.6. |
| `DAST_SUBMIT_FIELD` | string | The `id` or `name` of the element that when clicked submits the login form or the password form of a multi-page login process. [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9894) in GitLab 12.4. |
| `DAST_FIRST_SUBMIT_FIELD` | string | The `id` or `name` of the element that when clicked submits the username form of a multi-page login process. [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9894) in GitLab 12.4. |
| `DAST_ZAP_CLI_OPTIONS` | string | ZAP server command-line options. For example, `-Xmx3072m` would set the Java maximum memory allocation pool size. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_ZAP_LOG_CONFIGURATION` | string | Set to a semicolon-separated list of additional log4j properties for the ZAP Server. For example, `log4j.logger.org.parosproxy.paros.network.HttpSender=DEBUG;log4j.logger.com.crawljax=DEBUG` |
| `DAST_AUTH_EXCLUDE_URLS` | URLs | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/289959)** in GitLab 14.0. Replaced by `DAST_EXCLUDE_URLS`. The URLs to skip during the authenticated scan; comma-separated. Regular expression syntax can be used to match multiple URLs. For example, `.*` matches an arbitrary character sequence. Not supported for API scans. |
| `DAST_AGGREGATE_VULNERABILITIES` | boolean | Vulnerability aggregation is set to `true` by default. To disable this feature and see each vulnerability individually set to `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/254043) in GitLab 14.0. |
| `DAST_MAX_URLS_PER_VULNERABILITY` | number | The maximum number of URLs reported for a single vulnerability. `DAST_MAX_URLS_PER_VULNERABILITY` is set to `50` by default. To list all the URLs set to `0`. [Introduced](https://gitlab.com/gitlab-org/security-products/dast/-/merge_requests/433) in GitLab 13.12. |
| `DAST_AUTH_REPORT` | boolean | Used in combination with exporting the `gl-dast-debug-auth-report.html` artifact to aid in debugging authentication issues. |
| `DAST_AUTH_VERIFICATION_URL` <sup>1</sup> | URL | A URL only accessible to logged in users that DAST can use to confirm successful authentication. If provided, DAST exits if it cannot access the URL. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/207335) in GitLab 13.8. |
| `DAST_AUTH_VERIFICATION_SELECTOR` | selector | Verifies successful authentication by checking for presence of a selector once the login form has been submitted. Example: `css:.user-photo` |
| `DAST_AUTH_VERIFICATION_LOGIN_FORM` | boolean | Verifies successful authentication by checking for the lack of a login form once the login form has been submitted. |
| `DAST_ADVERTISE_SCAN` | boolean | Set to `true` to add a `Via` header to every request sent, advertising that the request was sent as part of a GitLab DAST scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/334947) in GitLab 14.1. |
| CI/CD variable | Type | Description |
|:-------------------------------------------------|:--------------|:------------------------------|
| `DAST_ADVERTISE_SCAN` | boolean | Set to `true` to add a `Via` header to every request sent, advertising that the request was sent as part of a GitLab DAST scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/334947) in GitLab 14.1. |
| `DAST_AGGREGATE_VULNERABILITIES` | boolean | Vulnerability aggregation is set to `true` by default. To disable this feature and see each vulnerability individually set to `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/254043) in GitLab 14.0. |
| `DAST_API_HOST_OVERRIDE` <sup>1</sup> | string | Used to override domains defined in API specification files. Only supported when importing the API specification from a URL. Example: `example.com:8080`. |
| `DAST_API_OPENAPI` | URL or string | The API specification to import. The specification can be hosted at a URL, or the name of a file present in the `/zap/wrk` directory. The variable `DAST_WEBSITE` must be specified if this is omitted. |
| `DAST_API_SPECIFICATION` <sup>1</sup> | URL or string | [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/290241) in GitLab 13.12 and replaced by `DAST_API_OPENAPI`. To be removed in GitLab 15.0. The API specification to import. The specification can be hosted at a URL, or the name of a file present in the `/zap/wrk` directory. The variable `DAST_WEBSITE` must be specified if this is omitted. |
| `DAST_AUTH_REPORT` <sup>2</sup> | boolean | Used in combination with exporting the `gl-dast-debug-auth-report.html` artifact to aid in debugging authentication issues. |
| `DAST_AUTH_EXCLUDE_URLS` <sup>2</sup> | URLs | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/289959)** in GitLab 14.0. Replaced by `DAST_EXCLUDE_URLS`. The URLs to skip during the authenticated scan; comma-separated. Regular expression syntax can be used to match multiple URLs. For example, `.*` matches an arbitrary character sequence. Not supported for API scans. |
| `DAST_AUTH_URL` <sup>1,2</sup> | URL | The URL of the page containing the sign-in HTML form on the target website. `DAST_USERNAME` and `DAST_PASSWORD` are submitted with the login form to create an authenticated scan. Not supported for API scans. Example: `https://login.example.com`. |
| `DAST_AUTH_VERIFICATION_LOGIN_FORM` <sup>2</sup> | boolean | Verifies successful authentication by checking for the lack of a login form once the login form has been submitted. |
| `DAST_AUTH_VERIFICATION_SELECTOR` <sup>2</sup> | selector | Verifies successful authentication by checking for presence of a selector once the login form has been submitted. Example: `css:.user-photo`. |
| `DAST_AUTH_VERIFICATION_URL` <sup>1,2</sup> | URL | A URL only accessible to logged in users that DAST can use to confirm successful authentication. If provided, DAST exits if it cannot access the URL. Example: `"http://example.com/loggedin_page"`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/207335) in GitLab 13.8. |
| `DAST_AUTO_UPDATE_ADDONS` | boolean | ZAP add-ons are pinned to specific versions in the DAST Docker image. Set to `true` to download the latest versions when the scan starts. Default: `false`. |
| `DAST_BROWSER_PATH_TO_LOGIN_FORM` <sup>1,2</sup> | selector | Comma-separated list of selectors that will be clicked on prior to attempting to enter `DAST_USERNAME` and `DAST_PASSWORD` into the login form. Example: `"css:.navigation-menu,css:.login-menu-item"`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/326633) in GitLab 14.1. |
| `DAST_DEBUG` <sup>1</sup> | boolean | Enable debug message output. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_EXCLUDE_RULES` | string | Set to a comma-separated list of Vulnerability Rule IDs to exclude them from running during the scan. Rule IDs are numbers and can be found from the DAST log or on the [ZAP project](https://www.zaproxy.org/docs/alerts/). For example, `HTTP Parameter Override` has a rule ID of `10026`. Cannot be used when `DAST_ONLY_INCLUDE_RULES` is set. **Note:** In earlier versions of GitLab the excluded rules were executed but vulnerabilities they generated were suppressed. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118641) in GitLab 12.10. |
| `DAST_EXCLUDE_URLS` <sup>1,2</sup> | URLs | The URLs to skip during the authenticated scan; comma-separated. Regular expression syntax can be used to match multiple URLs. For example, `.*` matches an arbitrary character sequence. Not supported for API scans. Example, `http://example.com/sign-out`. |
| `DAST_FIRST_SUBMIT_FIELD` <sup>2</sup> | string | The `id` or `name` of the element that when clicked submits the username form of a multi-page login process. For example, `css:button[type='user-submit']`. [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9894) in GitLab 12.4. |
| `DAST_FULL_SCAN_DOMAIN_VALIDATION_REQUIRED` | boolean | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/293595)** in GitLab 14.0. Set to `true` to require domain validation when running DAST full scans. Not supported for API scans. Default: `false` |
| `DAST_FULL_SCAN_ENABLED` <sup>1</sup> | boolean | Set to `true` to run a [ZAP Full Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Full-Scan) instead of a [ZAP Baseline Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Baseline-Scan). Default: `false` |
| `DAST_HTML_REPORT` | string | The filename of the HTML report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_INCLUDE_ALPHA_VULNERABILITIES` | boolean | Set to `true` to include alpha passive and active scan rules. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_MARKDOWN_REPORT` | string | The filename of the Markdown report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_MASK_HTTP_HEADERS` | string | Comma-separated list of request and response headers to be masked (GitLab 13.1). Must contain **all** headers to be masked. Refer to [list of headers that are masked by default](#hide-sensitive-information). |
| `DAST_MAX_URLS_PER_VULNERABILITY` | number | The maximum number of URLs reported for a single vulnerability. `DAST_MAX_URLS_PER_VULNERABILITY` is set to `50` by default. To list all the URLs set to `0`. [Introduced](https://gitlab.com/gitlab-org/security-products/dast/-/merge_requests/433) in GitLab 13.12. |
| `DAST_ONLY_INCLUDE_RULES` | string | Set to a comma-separated list of Vulnerability Rule IDs to configure the scan to run only them. Rule IDs are numbers and can be found from the DAST log or on the [ZAP project](https://www.zaproxy.org/docs/alerts/). Cannot be used when `DAST_EXCLUDE_RULES` is set. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/250651) in GitLab 13.12. |
| `DAST_PASSWORD` <sup>1,2</sup> | string | The password to authenticate to in the website. Example: `P@55w0rd!` |
| `DAST_PASSWORD_FIELD` <sup>1,2</sup> | string | The selector of password field at the sign-in HTML form. Example: `id:password` |
| `DAST_PATHS` | string | Set to a comma-separated list of URLs for DAST to scan. For example, `/page1.html,/category1/page3.html,/page2.html`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214120) in GitLab 13.4. |
| `DAST_PATHS_FILE` | string | The file path containing the paths within `DAST_WEBSITE` to scan. The file must be plain text with one path per line. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258825) in GitLab 13.6. |
| `DAST_REQUEST_HEADERS` <sup>1</sup> | string | Set to a comma-separated list of request header names and values. Headers are added to every request made by DAST. For example, `Cache-control: no-cache,User-Agent: DAST/1.0` |
| `DAST_SKIP_TARGET_CHECK` | boolean | Set to `true` to prevent DAST from checking that the target is available before scanning. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229067) in GitLab 13.8. |
| `DAST_SPIDER_MINS` <sup>1</sup> | number | The maximum duration of the spider scan in minutes. Set to `0` for unlimited. Default: One minute, or unlimited when the scan is a full scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_SPIDER_START_AT_HOST` | boolean | Set to `false` to prevent DAST from resetting the target to its host before scanning. When `true`, non-host targets `http://test.site/some_path` is reset to `http://test.site` before scan. Default: `true`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258805) in GitLab 13.6. |
| `DAST_SUBMIT_FIELD` <sup>2</sup> | string | The `id` or `name` of the element that when clicked submits the login form or the password form of a multi-page login process. For example, `css:button[type='submit']`. [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9894) in GitLab 12.4. |
| `DAST_TARGET_AVAILABILITY_TIMEOUT` <sup>1</sup> | number | Time limit in seconds to wait for target availability. |
| `DAST_USE_AJAX_SPIDER` <sup>1</sup> | boolean | Set to `true` to use the AJAX spider in addition to the traditional spider, useful for crawling sites that require JavaScript. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_USERNAME` <sup>1,2</sup> | string | The username to authenticate to in the website. Example: `admin` |
| `DAST_USERNAME_FIELD` <sup>1,2</sup> | string | The selector of username field at the sign-in HTML form. Example: `name:username` |
| `DAST_XML_REPORT` | string | The filename of the XML report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_WEBSITE` <sup>1</sup> | URL | The URL of the website to scan. The variable `DAST_API_OPENAPI` must be specified if this is omitted. |
| `DAST_ZAP_CLI_OPTIONS` | string | ZAP server command-line options. For example, `-Xmx3072m` would set the Java maximum memory allocation pool size. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
| `DAST_ZAP_LOG_CONFIGURATION` | string | Set to a semicolon-separated list of additional log4j properties for the ZAP Server. Example: `log4j.logger.org.parosproxy.paros.network.HttpSender=DEBUG;log4j.logger.com.crawljax=DEBUG` |
| `SECURE_ANALYZERS_PREFIX` | URL | Set the Docker registry base address from which to download the analyzer. |
1. Available to an on-demand DAST scan.
1. Used for authentication.
#### Selectors

View File

@ -45,10 +45,12 @@ The following table lists project permissions available for each role:
| Action | Guest | Reporter | Developer |Maintainer| Owner |
|---------------------------------------------------|---------|------------|-------------|----------|--------|
| Assign issues | ✓ (*16*)| ✓ | ✓ | ✓ | ✓ |
| Create confidential issue | ✓ | ✓ | ✓ | ✓ | ✓ |
| Create new issue | ✓ | ✓ | ✓ | ✓ | ✓ |
| Download and browse job artifacts | ✓ (*3*) | ✓ | ✓ | ✓ | ✓ |
| Download project | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| Label issues | ✓ (*16*)| ✓ | ✓ | ✓ | ✓ |
| Leave comments | ✓ | ✓ | ✓ | ✓ | ✓ |
| Manage user-starred metrics dashboards (*7*) | ✓ | ✓ | ✓ | ✓ | ✓ |
| Pull project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
@ -56,6 +58,7 @@ The following table lists project permissions available for each role:
| See a job log | ✓ (*3*) | ✓ | ✓ | ✓ | ✓ |
| See a list of jobs | ✓ (*3*) | ✓ | ✓ | ✓ | ✓ |
| See linked issues | ✓ | ✓ | ✓ | ✓ | ✓ |
| Set issue weight | ✓ (*16*)| ✓ | ✓ | ✓ | ✓ |
| View [Design Management](project/issues/design_management.md) pages | ✓ | ✓ | ✓ | ✓ | ✓ |
| View [Releases](project/releases/index.md) | ✓ (*6*) | ✓ | ✓ | ✓ | ✓ |
| View a time tracking report | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
@ -73,13 +76,11 @@ The following table lists project permissions available for each role:
| View wiki pages | ✓ | ✓ | ✓ | ✓ | ✓ |
| Archive [test case](../ci/test_cases/index.md) | | ✓ | ✓ | ✓ | ✓ |
| Archive/reopen requirements **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
| Assign issues | | ✓ | ✓ | ✓ | ✓ |
| Assign reviewers | | ✓ | ✓ | ✓ | ✓ |
| Create code snippets | | ✓ | ✓ | ✓ | ✓ |
| Create new [test case](../ci/test_cases/index.md) | | ✓ | ✓ | ✓ | ✓ |
| Create/edit requirements **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
| Import/export requirements **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
| Label issues | | ✓ | ✓ | ✓ | ✓ |
| Lock issue threads | | ✓ | ✓ | ✓ | ✓ |
| Manage issue tracker | | ✓ | ✓ | ✓ | ✓ |
| Manage labels | | ✓ | ✓ | ✓ | ✓ |
@ -94,7 +95,6 @@ The following table lists project permissions available for each role:
| See a list of merge requests | | ✓ | ✓ | ✓ | ✓ |
| See environments | | ✓ | ✓ | ✓ | ✓ |
| [Set issue estimate and record time spent](project/time_tracking.md) | | ✓ | ✓ | ✓ | ✓ |
| Set issue weight | | ✓ | ✓ | ✓ | ✓ |
| View CI/CD analytics | | ✓ | ✓ | ✓ | ✓ |
| View Code Review analytics **(PREMIUM)** | | ✓ | ✓ | ✓ | ✓ |
| View confidential issues | (*2*) | ✓ | ✓ | ✓ | ✓ |
@ -216,6 +216,7 @@ The following table lists project permissions available for each role:
[project visibility](../public_access/public_access.md) is set to private.
1. Attached design files are moved together with the issue even if the user doesn't have the
Developer role.
1. Guest users can set metadata (for example, labels, assignees, or milestones) when creating an issue.
## Project features permissions

View File

@ -5787,6 +5787,9 @@ msgstr ""
msgid "CI configuration validated, including all configuration added with the %{codeStart}includes%{codeEnd} keyword. %{link}"
msgstr ""
msgid "CI minutes"
msgstr ""
msgid "CI settings"
msgstr ""
@ -37732,6 +37735,9 @@ msgstr ""
msgid "You have set up 2FA for your account! If you lose access to your 2FA device, you can use your recovery codes to access your account. Alternatively, if you upload an SSH key, you can %{anchorOpen}use that key to generate additional recovery codes%{anchorClose}."
msgstr ""
msgid "You have successfully purchased %{product}. You'll receive a receipt by mail."
msgstr ""
msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. Youll receive a receipt via email."
msgstr ""

View File

@ -7,9 +7,13 @@ RSpec.describe JiraConnect::SubscriptionsController do
describe '#index' do
before do
request.headers['Accept'] = content_type
get :index, params: { jwt: jwt }
end
let(:content_type) { 'text/html' }
context 'without JWT' do
let(:jwt) { nil }
@ -29,13 +33,55 @@ RSpec.describe JiraConnect::SubscriptionsController do
it 'removes X-Frame-Options to allow rendering in iframe' do
expect(response.headers['X-Frame-Options']).to be_nil
end
context 'with JSON format' do
let_it_be(:subscription) { create(:jira_connect_subscription, installation: installation) }
let(:content_type) { 'application/json' }
it 'renders the relevant data as JSON', :aggregate_failures do
expect(json_response).to include('groups_path' => api_v4_groups_path(params: { min_access_level: Gitlab::Access::MAINTAINER, skip_groups: [subscription.namespace_id] }))
expect(json_response).to include(
'subscriptions' => [
'group' => {
'name' => subscription.namespace.name,
'avatar_url' => subscription.namespace.avatar_url,
'full_name' => subscription.namespace.full_name,
'description' => subscription.namespace.description
},
'created_at' => subscription.created_at.iso8601(3),
'unlink_path' => jira_connect_subscription_path(subscription)
]
)
expect(json_response).to include('subscriptions_path' => jira_connect_subscriptions_path)
end
context 'when not signed in to GitLab' do
it 'contains a login path' do
expect(json_response).to include('login_path' => jira_connect_users_path)
end
end
context 'when signed in to GitLab' do
let(:user) { create(:user) }
before do
sign_in(user)
get :index, params: { jwt: jwt }
end
it 'does not contain a login path' do
expect(json_response).to include('login_path' => nil)
end
end
end
end
end
describe '#create' do
let(:group) { create(:group) }
let(:user) { create(:user) }
let(:current_user) { user }
before do
group.add_maintainer(user)

View File

@ -174,6 +174,8 @@ RSpec.describe Projects::ServicesController do
let(:redirect_url) { edit_project_service_path(project, integration) }
before do
stub_jira_integration_test
put :update, params: params
end
@ -222,12 +224,48 @@ RSpec.describe Projects::ServicesController do
end
end
context 'when param `inherit_from_id` is set to some value' do
let(:instance_service) { create(:jira_integration, :instance) }
let(:integration_params) { { inherit_from_id: instance_service.id } }
context 'when param `inherit_from_id` is set to an instance integration' do
let(:instance_integration) { create(:jira_integration, :instance, url: 'http://instance.com', password: 'instance') }
let(:integration_params) { { inherit_from_id: instance_integration.id, url: 'http://custom.com', password: 'custom' } }
it 'sets inherit_from_id to value' do
expect(integration.reload.inherit_from_id).to eq(instance_service.id)
it 'ignores submitted params and inherits instance settings' do
expect(integration.reload).to have_attributes(
inherit_from_id: instance_integration.id,
url: instance_integration.url,
password: instance_integration.password
)
end
end
context 'when param `inherit_from_id` is set to a group integration' do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
let_it_be(:jira_integration) { create(:jira_integration, project: project) }
let(:group_integration) { create(:jira_integration, group: group, project: nil, url: 'http://group.com', password: 'group') }
let(:integration_params) { { inherit_from_id: group_integration.id, url: 'http://custom.com', password: 'custom' } }
it 'ignores submitted params and inherits group settings' do
expect(integration.reload).to have_attributes(
inherit_from_id: group_integration.id,
url: group_integration.url,
password: group_integration.password
)
end
end
context 'when param `inherit_from_id` is set to an unrelated group' do
let_it_be(:group) { create(:group) }
let(:group_integration) { create(:jira_integration, group: group, project: nil, url: 'http://group.com', password: 'group') }
let(:integration_params) { { inherit_from_id: group_integration.id, url: 'http://custom.com', password: 'custom' } }
it 'ignores the param and saves the submitted settings' do
expect(integration.reload).to have_attributes(
inherit_from_id: nil,
url: 'http://custom.com',
password: 'custom'
)
end
end
end

View File

@ -0,0 +1,91 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'User uses inherited settings', :js do
include JiraServiceHelper
include_context 'project service activation'
before do
stub_jira_integration_test
end
shared_examples 'inherited settings' do
let_it_be(:project_settings) { { url: 'http://project.com', password: 'project' } }
describe 'switching from inherited to custom settings' do
let_it_be(:integration) { create(:jira_integration, project: project, inherit_from_id: parent_integration.id, **project_settings) }
it 'clears the form fields and saves the entered values' do
visit_project_integration('Jira')
expect(page).not_to have_button('Use custom settings')
expect(page).to have_field('Web URL', with: parent_settings[:url], readonly: true)
expect(page).to have_field('Enter new password or API token', with: '', readonly: true)
click_on 'Use default settings'
click_on 'Use custom settings'
expect(page).not_to have_button('Use default settings')
expect(page).to have_field('Web URL', with: project_settings[:url], readonly: false)
expect(page).to have_field('Enter new password or API token', with: '', readonly: false)
fill_in 'Web URL', with: 'http://custom.com'
fill_in 'Enter new password or API token', with: 'custom'
click_save_integration
expect(page).to have_text('Jira settings saved and active.')
expect(integration.reload).to have_attributes(
inherit_from_id: nil,
url: 'http://custom.com',
password: 'custom'
)
end
end
describe 'switching from custom to inherited settings' do
let_it_be(:integration) { create(:jira_integration, project: project, **project_settings) }
it 'resets the form fields, makes them read-only, and saves the inherited values' do
visit_project_integration('Jira')
expect(page).not_to have_button('Use default settings')
expect(page).to have_field('URL', with: project_settings[:url], readonly: false)
expect(page).to have_field('Enter new password or API token', with: '', readonly: false)
click_on 'Use custom settings'
click_on 'Use default settings'
expect(page).not_to have_button('Use custom settings')
expect(page).to have_field('URL', with: parent_settings[:url], readonly: true)
expect(page).to have_field('Enter new password or API token', with: '', readonly: true)
click_save_integration
expect(page).to have_text('Jira settings saved and active.')
expect(integration.reload).to have_attributes(
inherit_from_id: parent_integration.id,
**parent_settings
)
end
end
end
context 'with instance settings' do
let_it_be(:parent_settings) { { url: 'http://instance.com', password: 'instance' } }
let_it_be(:parent_integration) { create(:jira_integration, :instance, **parent_settings) }
it_behaves_like 'inherited settings'
end
context 'with group settings' do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
let_it_be(:parent_settings) { { url: 'http://group.com', password: 'group' } }
let_it_be(:parent_integration) { create(:jira_integration, group: group, project: nil, **parent_settings) }
it_behaves_like 'inherited settings'
end
end

View File

@ -57,6 +57,56 @@ RSpec.describe 'User page' do
end
end
context 'location' do
let_it_be(:location) { 'San Francisco, CA' }
context 'when location is set' do
let_it_be(:user) { create(:user, location: location) }
it 'shows location' do
subject
expect(page).to have_content(location)
end
end
context 'when location is not set' do
it 'does not show location' do
subject
expect(page).not_to have_content(location)
end
end
end
context 'timezone' do
let_it_be(:timezone) { 'America/Los_Angeles' }
before do
travel_to Time.find_zone(timezone).local(2021, 7, 20, 15, 30, 45)
end
context 'when timezone is set' do
let_it_be(:user) { create(:user, timezone: timezone) }
it 'shows local time' do
subject
expect(page).to have_content('3:30 PM')
end
end
context 'when timezone is invalid' do
let_it_be(:user) { create(:user, timezone: 'Foo/Bar') }
it 'shows local time using the configured default timezone (UTC in this case)' do
subject
expect(page).to have_content('10:30 PM')
end
end
end
context 'follow/unfollow and followers/following' do
let_it_be(:followee) { create(:user) }
let_it_be(:follower) { create(:user) }

View File

@ -6,10 +6,11 @@ import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
import PackagesApp from '~/packages_and_registries/package_registry/components/details/app.vue';
import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
import { FETCH_PACKAGE_DETAILS_ERROR_MESSAGE } from '~/packages_and_registries/package_registry/constants';
import getPackageDetails from '~/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql';
import { packageDetailsQuery, packageData } from '../../mock_data';
import { packageDetailsQuery, packageData, emptyPackageDetailsQuery } from '../../mock_data';
jest.mock('~/flash');
@ -19,6 +20,18 @@ describe('PackagesApp', () => {
let wrapper;
let apolloProvider;
const provide = {
packageId: '111',
titleComponent: 'PackageTitle',
projectName: 'projectName',
canDelete: 'canDelete',
svgPath: 'svgPath',
npmPath: 'npmPath',
npmHelpPath: 'npmHelpPath',
projectListUrl: 'projectListUrl',
groupListUrl: 'groupListUrl',
};
function createComponent({ resolver = jest.fn().mockResolvedValue(packageDetailsQuery()) } = {}) {
localVue.use(VueApollo);
@ -28,29 +41,22 @@ describe('PackagesApp', () => {
wrapper = shallowMount(PackagesApp, {
localVue,
apolloProvider,
provide: {
packageId: '111',
titleComponent: 'PackageTitle',
projectName: 'projectName',
canDelete: 'canDelete',
svgPath: 'svgPath',
npmPath: 'npmPath',
npmHelpPath: 'npmHelpPath',
projectListUrl: 'projectListUrl',
groupListUrl: 'groupListUrl',
},
provide,
});
}
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
const findPackageTitle = () => wrapper.findComponent(PackageTitle);
const findPackageHistory = () => wrapper.findComponent(PackageHistory);
afterEach(() => {
wrapper.destroy();
});
it('renders an empty state component', () => {
createComponent();
it('renders an empty state component', async () => {
createComponent({ resolver: jest.fn().mockResolvedValue(emptyPackageDetailsQuery) });
await waitForPromises();
expect(findEmptyState().exists()).toBe(true);
});
@ -77,4 +83,16 @@ describe('PackagesApp', () => {
}),
);
});
it('renders history and has the right props', async () => {
createComponent();
await waitForPromises();
expect(findPackageHistory().exists()).toBe(true);
expect(findPackageHistory().props()).toMatchObject({
packageEntity: expect.objectContaining(packageData()),
projectName: provide.projectName,
});
});
});

View File

@ -1,7 +1,10 @@
import { GlLink, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { stubComponent } from 'helpers/stub_component';
import { mavenPackage, mockPipelineInfo } from 'jest/packages/mock_data';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import {
packageData,
packagePipelines,
} from 'jest/packages_and_registries/package_registry/mock_data';
import { HISTORY_PIPELINES_LIMIT } from '~/packages/details/constants';
import component from '~/packages_and_registries/package_registry/components/details/package_history.vue';
import HistoryItem from '~/vue_shared/components/registry/history_item.vue';
@ -11,14 +14,16 @@ describe('Package History', () => {
let wrapper;
const defaultProps = {
projectName: 'baz project',
packageEntity: { ...mavenPackage },
packageEntity: { ...packageData() },
};
const [onePipeline] = packagePipelines();
const createPipelines = (amount) =>
[...Array(amount)].map((x, index) => ({ ...mockPipelineInfo, id: index + 1 }));
[...Array(amount)].map((x, index) => packagePipelines({ id: index + 1 })[0]);
const mountComponent = (props) => {
wrapper = shallowMount(component, {
wrapper = shallowMountExtended(component, {
propsData: { ...defaultProps, ...props },
stubs: {
HistoryItem: stubComponent(HistoryItem, {
@ -31,14 +36,13 @@ describe('Package History', () => {
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
const findHistoryElement = (testId) => wrapper.find(`[data-testid="${testId}"]`);
const findElementLink = (container) => container.find(GlLink);
const findElementTimeAgo = (container) => container.find(TimeAgoTooltip);
const findTitle = () => wrapper.find('[data-testid="title"]');
const findTimeline = () => wrapper.find('[data-testid="timeline"]');
const findHistoryElement = (testId) => wrapper.findByTestId(testId);
const findElementLink = (container) => container.findComponent(GlLink);
const findElementTimeAgo = (container) => container.findComponent(TimeAgoTooltip);
const findTitle = () => wrapper.findByTestId('title');
const findTimeline = () => wrapper.findByTestId('timeline');
it('has the correct title', () => {
mountComponent();
@ -59,23 +63,25 @@ describe('Package History', () => {
expect.arrayContaining(['timeline', 'main-notes-list', 'notes']),
);
});
describe.each`
name | amount | icon | text | timeAgoTooltip | link
${'created-on'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'clock'} | ${'Test package version 1.0.0 was first created'} | ${mavenPackage.created_at} | ${null}
${'first-pipeline-commit'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'commit'} | ${'Created by commit #sha-baz on branch branch-name'} | ${null} | ${mockPipelineInfo.project.commit_url}
${'first-pipeline-pipeline'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'pipeline'} | ${'Built by pipeline #1 triggered by foo'} | ${mockPipelineInfo.created_at} | ${mockPipelineInfo.project.pipeline_url}
${'published'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'package'} | ${'Published to the baz project Package Registry'} | ${mavenPackage.created_at} | ${null}
${'archived'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'history'} | ${'Package has 1 archived update'} | ${null} | ${null}
${'archived'} | ${HISTORY_PIPELINES_LIMIT + 3} | ${'history'} | ${'Package has 2 archived updates'} | ${null} | ${null}
${'pipeline-entry'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'pencil'} | ${'Package updated by commit #sha-baz on branch branch-name, built by pipeline #3, and published to the registry'} | ${mavenPackage.created_at} | ${mockPipelineInfo.project.commit_url}
name | amount | icon | text | timeAgoTooltip | link
${'created-on'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'clock'} | ${'@gitlab-org/package-15 version 1.0.0 was first created'} | ${packageData().createdAt} | ${null}
${'first-pipeline-commit'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'commit'} | ${'Created by commit #b83d6e39 on branch master'} | ${null} | ${onePipeline.commitPath}
${'first-pipeline-pipeline'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'pipeline'} | ${'Built by pipeline #1 triggered by Administrator'} | ${onePipeline.createdAt} | ${onePipeline.path}
${'published'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'package'} | ${'Published to the baz project Package Registry'} | ${packageData().createdAt} | ${null}
${'archived'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'history'} | ${'Package has 1 archived update'} | ${null} | ${null}
${'archived'} | ${HISTORY_PIPELINES_LIMIT + 3} | ${'history'} | ${'Package has 2 archived updates'} | ${null} | ${null}
${'pipeline-entry'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'pencil'} | ${'Package updated by commit #b83d6e39 on branch master, built by pipeline #3, and published to the registry'} | ${packageData().createdAt} | ${onePipeline.commitPath}
`(
'with $amount pipelines history element $name',
({ name, icon, text, timeAgoTooltip, link, amount }) => {
let element;
beforeEach(() => {
const packageEntity = { ...packageData(), pipelines: { nodes: createPipelines(amount) } };
mountComponent({
packageEntity: { ...mavenPackage, pipelines: createPipelines(amount) },
packageEntity,
});
element = findHistoryElement(name);
});

View File

@ -6,11 +6,21 @@ export const packageTags = () => [
export const packagePipelines = (extend) => [
{
commitPath: '/namespace14/project14/-/commit/b83d6e391c22777fca1ed3012fce84f633d7fed0',
createdAt: '2020-08-17T14:23:32Z',
id: 'gid://gitlab/Ci::Pipeline/36',
path: '/namespace14/project14/-/pipelines/36',
name: 'project14',
ref: 'master',
sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0',
project: {
name: 'project14',
webUrl: 'http://gdk.test:3000/namespace14/project14',
__typename: 'Project',
},
user: {
name: 'Administrator',
},
...extend,
__typename: 'Pipeline',
},
@ -68,3 +78,11 @@ export const packageDetailsQuery = () => ({
},
},
});
export const emptyPackageDetailsQuery = () => ({
data: {
package: {
__typename: 'PackageDetailsType',
},
},
});

View File

@ -68,4 +68,24 @@ RSpec.describe TimeZoneHelper, :aggregate_failures do
end
end
end
describe '#local_time' do
let_it_be(:timezone) { 'America/Los_Angeles' }
before do
travel_to Time.find_zone(timezone).local(2021, 7, 20, 15, 30, 45)
end
context 'when a valid timezone is passed' do
it 'returns local time' do
expect(helper.local_time(timezone)).to eq('3:30 PM')
end
end
context 'when an invalid timezone is passed' do
it 'returns local time using the configured default timezone (UTC in this case)' do
expect(helper.local_time('Foo/Bar')).to eq('10:30 PM')
end
end
end
end

View File

@ -4,7 +4,7 @@ require 'spec_helper'
require_migration!
RSpec.describe ScheduleDeleteOrphanedDeployments, :sidekiq, schema: 20210617161348 do
RSpec.describe RescheduleDeleteOrphanedDeployments, :sidekiq, schema: 20210617161348 do
let!(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') }
let!(:project) { table(:projects).create!(namespace_id: namespace.id) }
let!(:environment) { table(:environments).create!(name: 'production', slug: 'production', project_id: project.id) }
@ -22,6 +22,31 @@ RSpec.describe ScheduleDeleteOrphanedDeployments, :sidekiq, schema: 202106171613
stub_const("#{described_class}::BATCH_SIZE", 1)
end
it 'steal existing background migration jobs' do
expect(Gitlab::BackgroundMigration).to receive(:steal).with('DeleteOrphanedDeployments')
migrate!
end
it 'cleans up background migration jobs tracking records' do
old_successful_job = background_migration_jobs.create!(
class_name: 'DeleteOrphanedDeployments',
status: Gitlab::Database::BackgroundMigrationJob.statuses[:succeeded],
arguments: [table(:deployments).minimum(:id), table(:deployments).minimum(:id)]
)
old_pending_job = background_migration_jobs.create!(
class_name: 'DeleteOrphanedDeployments',
status: Gitlab::Database::BackgroundMigrationJob.statuses[:pending],
arguments: [table(:deployments).maximum(:id), table(:deployments).maximum(:id)]
)
migrate!
expect { old_successful_job.reload }.to raise_error(ActiveRecord::RecordNotFound)
expect { old_pending_job.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
it 'schedules DeleteOrphanedDeployments background jobs' do
Sidekiq::Testing.fake! do
freeze_time do

View File

@ -0,0 +1,34 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe JiraConnect::AppDataSerializer do
describe '#as_json' do
subject(:app_data_json) { described_class.new(subscriptions, signed_in).as_json }
let_it_be(:subscriptions) { create_list(:jira_connect_subscription, 2) }
let(:signed_in) { false }
it 'uses the subscription entity' do
expect(JiraConnect::SubscriptionEntity).to receive(:represent).with(subscriptions)
app_data_json
end
it 'includes a group path with already subscribed namespaces as skip_groups' do
expected_path = "/api/v4/groups?min_access_level=40&skip_groups%5B%5D=#{subscriptions.first.namespace_id}&skip_groups%5B%5D=#{subscriptions.last.namespace_id}"
expect(app_data_json).to include(groups_path: expected_path)
end
it { is_expected.to include(subscriptions_path: '/-/jira_connect/subscriptions') }
it { is_expected.to include(login_path: '/-/jira_connect/users') }
context 'when signed in' do
let(:signed_in) { true }
it { is_expected.to include(login_path: nil) }
end
end
end

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe JiraConnect::GroupEntity do
subject do
described_class.new(subscription.namespace).as_json
end
let(:subscription) { create(:jira_connect_subscription) }
it 'contains all necessary elements of the group', :aggregate_failures do
expect(subject[:name]).to eq(subscription.namespace.name)
expect(subject[:avatar_url]).to eq(subscription.namespace.avatar_url)
expect(subject[:full_name]).to eq(subscription.namespace.full_name)
expect(subject[:description]).to eq(subscription.namespace.description)
end
end

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe JiraConnect::SubscriptionEntity do
subject do
described_class.new(subscription).as_json
end
let(:subscription) { create(:jira_connect_subscription) }
it 'contains all necessary elements of the subscription', :aggregate_failures do
expect(subject).to include(:created_at)
expect(subject[:unlink_path]).to eq("/-/jira_connect/subscriptions/#{subscription.id}")
expect(subject[:group]).to eq(
name: subscription.namespace.name,
avatar_url: subscription.namespace.avatar_url,
full_name: subscription.namespace.full_name,
description: subscription.namespace.description
)
end
end

View File

@ -55,6 +55,15 @@ RSpec.describe Boards::Issues::ListService do
it_behaves_like 'issues list service'
end
context 'when filtering by type' do
it 'only returns the specified type' do
issue = create(:labeled_issue, project: project, milestone: m1, labels: [development, p1], issue_type: 'incident')
params = { board_id: board.id, id: list1.id, issue_types: 'incident' }
expect(described_class.new(parent, user, params).execute).to eq [issue]
end
end
end
# rubocop: disable RSpec/MultipleMemoizedHelpers

View File

@ -76,4 +76,16 @@ RSpec.describe BulkUpdateIntegrationService do
end
end
end
it 'works with batch as an ActiveRecord::Relation' do
expect do
described_class.new(group_integration, Integration.where(id: integration.id)).execute
end.to change { integration.reload.url }.to(group_integration.url)
end
it 'works with batch as an array of ActiveRecord objects' do
expect do
described_class.new(group_integration, [integration]).execute
end.to change { integration.reload.url }.to(group_integration.url)
end
end

View File

@ -3,8 +3,8 @@
RSpec.shared_context 'project service activation' do
include_context 'integration activation'
let(:project) { create(:project) }
let(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
before do
project.add_maintainer(user)