Commit 2349eabc authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 134fe182
......@@ -18,8 +18,6 @@ import Icon from '~/vue_shared/components/icon.vue';
import { getParameterValues, mergeUrlParams, redirectTo } from '~/lib/utils/url_utility';
import invalidUrl from '~/lib/utils/invalid_url';
import DateTimePicker from './date_time_picker/date_time_picker.vue';
import MonitorTimeSeriesChart from './charts/time_series.vue';
import MonitorSingleStatChart from './charts/single_stat.vue';
import GraphGroup from './graph_group.vue';
import EmptyState from './empty_state.vue';
import TrackEventDirective from '~/vue_shared/directives/track_event';
......@@ -28,8 +26,6 @@ import { getTimeDiff, isValidDate, getAddMetricTrackingOptions } from '../utils'
export default {
components: {
VueDraggable,
MonitorTimeSeriesChart,
MonitorSingleStatChart,
PanelType,
GraphGroup,
EmptyState,
......
<script>
import { mapActions, mapState } from 'vuex';
import { getParameterValues, removeParams } from '~/lib/utils/url_utility';
import PanelType from 'ee_else_ce/monitoring/components/panel_type.vue';
import GraphGroup from './graph_group.vue';
import MonitorTimeSeriesChart from './charts/time_series.vue';
import { sidebarAnimationDuration } from '../constants';
import { getTimeDiff } from '../utils';
......@@ -11,7 +11,7 @@ let sidebarMutationObserver;
export default {
components: {
GraphGroup,
MonitorTimeSeriesChart,
PanelType,
},
props: {
dashboardUrl: {
......@@ -92,16 +92,13 @@ export default {
<template>
<div class="metrics-embed" :class="{ 'd-inline-flex col-lg-6 p-0': isSingleChart }">
<div v-if="charts.length" class="row w-100 m-n2 pb-4">
<monitor-time-series-chart
v-for="graphData in charts"
:key="graphData.title"
<panel-type
v-for="(graphData, graphIndex) in charts"
:key="`panel-type-${graphIndex}`"
class="w-100"
clipboard-text=""
:graph-data="graphData"
:container-width="elWidth"
:group-id="dashboardUrl"
:project-path="null"
:show-border="true"
:single-embed="isSingleChart"
/>
</div>
</div>
......
......@@ -47,6 +47,11 @@ export default {
required: false,
default: '',
},
groupId: {
type: String,
required: false,
default: 'panel-type-chart',
},
},
computed: {
...mapState('monitoringDashboard', ['deploymentData', 'projectPath']),
......@@ -117,7 +122,7 @@ export default {
:deployment-data="deploymentData"
:project-path="projectPath"
:thresholds="getGraphAlertValues(graphData.metrics)"
group-id="panel-type-chart"
:group-id="groupId"
>
<div class="d-flex align-items-center">
<alert-widget
......
......@@ -5,11 +5,9 @@ import initNotes from '~/init_notes';
import snippetEmbed from '~/snippet/snippet_embed';
document.addEventListener('DOMContentLoaded', () => {
if (!gon.features.snippetsVue) {
new LineHighlighter(); // eslint-disable-line no-new
new BlobViewer(); // eslint-disable-line no-new
initNotes();
new ZenMode(); // eslint-disable-line no-new
snippetEmbed();
}
new LineHighlighter(); // eslint-disable-line no-new
new BlobViewer(); // eslint-disable-line no-new
initNotes();
new ZenMode(); // eslint-disable-line no-new
snippetEmbed();
});
......@@ -28,6 +28,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
positions = @merge_request.note_positions_for_paths(diffs.diff_file_paths, current_user)
diffs.unfold_diff_files(positions.unfoldable)
diffs.write_cache
options = {
merge_request: @merge_request,
......
......@@ -34,3 +34,5 @@ module Emails
# rubocop: enable CodeReuse/ActiveRecord
end
end
Emails::Profile.prepend_if_ee('EE::Emails::Profile')
......@@ -5,6 +5,7 @@ module Ci
# We should migrate this object to actual database record in the future
class LegacyStage
include StaticModel
include Presentable
attr_reader :pipeline, :name
......
......@@ -27,8 +27,6 @@ class MergeRequest < ApplicationRecord
SORTING_PREFERENCE_FIELD = :merge_requests_sort
prepend_if_ee('::EE::MergeRequest') # rubocop: disable Cop/InjectEnterpriseEditionModule
belongs_to :target_project, class_name: "Project"
belongs_to :source_project, class_name: "Project"
belongs_to :merge_user, class_name: "User"
......@@ -1531,3 +1529,5 @@ class MergeRequest < ApplicationRecord
Gitlab::EtagCaching::Store.new.touch(key)
end
end
MergeRequest.prepend_if_ee('::EE::MergeRequest')
......@@ -70,3 +70,5 @@ class PersonalAccessToken < ApplicationRecord
"gitlab:personal_access_token:#{user_id}"
end
end
PersonalAccessToken.prepend_if_ee('EE::PersonalAccessToken')
# frozen_string_literal: true
module Ci
class LegacyStagePresenter < Gitlab::View::Presenter::Delegated
presents :legacy_stage
def latest_ordered_statuses
preload_statuses(legacy_stage.statuses.latest_ordered)
end
def retried_ordered_statuses
preload_statuses(legacy_stage.statuses.retried_ordered)
end
private
def preload_statuses(statuses)
statuses.tap do |statuses|
# rubocop: disable CodeReuse/ActiveRecord
ActiveRecord::Associations::Preloader.new.preload(preloadable_statuses(statuses), :tags)
# rubocop: enable CodeReuse/ActiveRecord
end
end
def preloadable_statuses(statuses)
statuses.reject do |status|
status.instance_of?(::GenericCommitStatus) || status.instance_of?(::Ci::Bridge)
end
end
end
end
......@@ -23,6 +23,9 @@
= f.label :session_expire_delay, _('Session duration (minutes)'), class: 'label-light'
= f.number_field :session_expire_delay, class: 'form-control'
%span.form-text.text-muted#session_expire_delay_help_block= _('GitLab restart is required to apply changes')
= render_if_exists 'admin/application_settings/personal_access_token_expiration_policy', form: f
.form-group
= f.label :user_oauth_applications, _('User OAuth applications'), class: 'label-bold'
.form-check
......
- stage = stage.present(current_user: current_user)
%tr
%th{ colspan: 10 }
%strong
......@@ -6,8 +8,8 @@
= ci_icon_for_status(stage.status)
&nbsp;
= stage.name.titleize
= render stage.statuses.latest_ordered, stage: false, ref: false, pipeline_link: false, allow_retry: true
= render stage.statuses.retried_ordered, stage: false, ref: false, pipeline_link: false, retried: true
= render stage.latest_ordered_statuses, stage: false, ref: false, pipeline_link: false, allow_retry: true
= render stage.retried_ordered_statuses, stage: false, ref: false, pipeline_link: false, retried: true
%tr
%td{ colspan: 10 }
&nbsp;
......@@ -18,6 +18,9 @@
.form-group.col-md-6
= f.label :expires_at, _('Expires at'), class: 'label-bold'
.input-icon-wrapper
= render_if_exists 'personal_access_tokens/callout_max_personal_access_token_lifetime'
= f.text_field :expires_at, class: "datepicker form-control", placeholder: 'YYYY-MM-DD'
.form-group
......
......@@ -4,16 +4,13 @@
- breadcrumb_title @snippet.to_reference
- page_title "#{@snippet.title} (#{@snippet.to_reference})", _("Snippets")
- if Feature.enabled?(:snippets_vue)
#js-snippet-view{ 'data-qa-selector': 'snippet_view' }
- else
= render 'shared/snippets/header'
= render 'shared/snippets/header'
.personal-snippets
%article.file-holder.snippet-file-content
= render 'shared/snippets/blob'
.personal-snippets
%article.file-holder.snippet-file-content
= render 'shared/snippets/blob'
.row-content-block.top-block.content-component-block
= render 'award_emoji/awards_block', awardable: @snippet, inline: true
.row-content-block.top-block.content-component-block
= render 'award_emoji/awards_block', awardable: @snippet, inline: true
#notes.limited-width-notes= render "shared/notes/notes_with_form", :autocomplete => false
#notes.limited-width-notes= render "shared/notes/notes_with_form", :autocomplete => false
---
title: Preserve merge train history
merge_request: 19864
author:
type: changed
......@@ -123,3 +123,5 @@
- [refresh_license_compliance_checks, 2]
- [design_management_new_version, 1]
- [epics, 2]
- [personal_access_tokens, 1]
# frozen_string_literal: true
class AddMaxPersonalAccessTokenLifetimeToApplicationSettings < ActiveRecord::Migration[5.2]
DOWNTIME = false
def change
add_column :application_settings, :max_personal_access_token_lifetime, :integer
end
end
# frozen_string_literal: true
class AddStateToMergeTrains < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
MERGE_TRAIN_STATUS_CREATED = 0 # Equivalent to MergeTrain.statuses[:created]
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default :merge_trains, :status, :integer, limit: 2, default: MERGE_TRAIN_STATUS_CREATED
end
def down
remove_column :merge_trains, :status
end
end
# frozen_string_literal: true
class AddIndexOnPersonalAccessTokensUserIdAndExpiresAt < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_NAME = 'index_pat_on_user_id_and_expires_at'
disable_ddl_transaction!
def up
add_concurrent_index :personal_access_tokens, [:user_id, :expires_at], name: INDEX_NAME, using: :btree
end
def down
remove_concurrent_index_by_name :personal_access_tokens, INDEX_NAME
end
end
# frozen_string_literal: true
class AddIndexOnStatusToMergeTrains < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_NAME = 'index_for_status_per_branch_per_project'
disable_ddl_transaction!
def up
add_concurrent_index :merge_trains, [:target_project_id, :target_branch, :status], name: INDEX_NAME
remove_concurrent_index :merge_trains, :target_project_id
end
def down
add_concurrent_index :merge_trains, :target_project_id
remove_concurrent_index :merge_trains, [:target_project_id, :target_branch, :status], name: INDEX_NAME
end
end
......@@ -325,6 +325,7 @@ ActiveRecord::Schema.define(version: 2019_12_02_031812) do
t.string "encrypted_asset_proxy_secret_key_iv"
t.string "static_objects_external_storage_url", limit: 255
t.string "static_objects_external_storage_auth_token", limit: 255
t.integer "max_personal_access_token_lifetime"
t.boolean "throttle_protected_paths_enabled", default: false, null: false
t.integer "throttle_protected_paths_requests_per_period", default: 10, null: false
t.integer "throttle_protected_paths_period_in_seconds", default: 60, null: false
......@@ -2524,9 +2525,10 @@ ActiveRecord::Schema.define(version: 2019_12_02_031812) do
t.datetime_with_timezone "updated_at", null: false
t.integer "target_project_id", null: false
t.text "target_branch", null: false
t.integer "status", limit: 2, default: 0, null: false
t.index ["merge_request_id"], name: "index_merge_trains_on_merge_request_id", unique: true
t.index ["pipeline_id"], name: "index_merge_trains_on_pipeline_id"
t.index ["target_project_id"], name: "index_merge_trains_on_target_project_id"
t.index ["target_project_id", "target_branch", "status"], name: "index_for_status_per_branch_per_project"
t.index ["user_id"], name: "index_merge_trains_on_user_id"
end
......@@ -2925,6 +2927,7 @@ ActiveRecord::Schema.define(version: 2019_12_02_031812) do
t.boolean "impersonation", default: false, null: false
t.string "token_digest"
t.index ["token_digest"], name: "index_personal_access_tokens_on_token_digest", unique: true
t.index ["user_id", "expires_at"], name: "index_pat_on_user_id_and_expires_at"
t.index ["user_id"], name: "index_personal_access_tokens_on_user_id"
end
......
......@@ -269,6 +269,7 @@ are listed in the descriptions of the relevant settings.
| `max_artifacts_size` | integer | no | Maximum artifacts size in MB |
| `max_attachment_size` | integer | no | Limit attachment size in MB |
| `max_pages_size` | integer | no | Maximum size of pages repositories in MB |
| `max_personal_access_token_lifetime` | integer | no | **(ULTIMATE ONLY)** Maximum allowable lifetime for personal access tokens in days |
| `metrics_enabled` | boolean | no | (**If enabled, requires:** `metrics_host`, `metrics_method_call_threshold`, `metrics_packet_size`, `metrics_pool_size`, `metrics_port`, `metrics_sample_interval` and `metrics_timeout`) Enable influxDB metrics. |
| `metrics_host` | string | required by: `metrics_enabled` | InfluxDB host. |
| `metrics_method_call_threshold` | integer | required by: `metrics_enabled` | A method call is only tracked when it takes longer than the given amount of milliseconds. |
......
......@@ -303,6 +303,41 @@ You are not required to use the same prefix or only slashes (`/`) in the dynamic
names. However, using this format will enable the [grouping similar environments](#grouping-similar-environments)
feature.
### Configuring Kubernetes deployments
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/27630) in GitLab 12.6.
If you are deploying to a [Kubernetes cluster](../user/project/clusters/index.md)
associated with your project, you can configure these deployments from your
`gitlab-ci.yml` file.
The following configuration options are supported:
- [`namespace`](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/)
In the following example, the job will deploy your application to the
`production` Kubernetes namespace.
```yaml
deploy:
stage: deploy
script:
- echo "Deploy to production server"
environment:
name: production
url: https://example.com
kubernetes:
namespace: production
only:
- master
```
NOTE: **Note:**
Kubernetes configuration is not supported for Kubernetes clusters
that are [managed by GitLab](../user/project/clusters/index.md#gitlab-managed-clusters).
To follow progress on support for Gitlab-managed clusters, see the
[relevant issue](https://gitlab.com/gitlab-org/gitlab/issues/38054).
### Complete example
The configuration in this section provides a full development workflow where your app is:
......
......@@ -1421,6 +1421,38 @@ The `stop_review_app` job is **required** to have the following keywords defined
- `stage` should be the same as the `review_app` in order for the environment
to stop automatically when the branch is deleted
#### `environment:kubernetes`
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/27630) in GitLab 12.6.
The `kubernetes` block is used to configure deployments to a
[Kubernetes cluster](../../user/project/clusters/index.md) that is associated with your project.
For example:
```yaml
deploy:
stage: deploy
script: make deploy-app
environment:
name: production
kubernetes:
namespace: production
```
This will set up the `deploy` job to deploy to the `production`
environment, using the `production`
[Kubernetes namespace](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/).
For more information, see
[Available settings for `kubernetes`](../environments.md#configuring-kubernetes-deployments).
NOTE: **Note:**
Kubernetes configuration is not supported for Kubernetes clusters
that are [managed by GitLab](../../user/project/clusters/index.md#gitlab-managed-clusters).
To follow progress on support for Gitlab-managed clusters, see the
[relevant issue](https://gitlab.com/gitlab-org/gitlab/issues/38054).
#### Dynamic environments
> - [Introduced][ce-6323] in GitLab 8.12 and GitLab Runner 1.6.
......
......@@ -84,3 +84,35 @@ add the line below to `/etc/gitlab/gitlab.rb` before increasing the max attachme
```
nginx['client_max_body_size'] = "200m"
```
## Limiting lifetime of personal access tokens **(ULTIMATE ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/3649) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.6.
Users can optionally specify an expiration date for
[personal access tokens](../../profile/personal_access_tokens.md).
This expiration date is not a requirement, and can be set to any arbitrary date.
Since personal access tokens are the only token needed for programmatic access to GitLab,
organizations with security requirements may want to enforce more protection to require
regular rotation of these tokens.
### Setting a limit
Only a GitLab administrator can set a limit. Leaving it empty means
there are no restrictions.
To set a limit on how long personal access tokens are valid:
1. Navigate to **Admin Area > Settings > General**.
1. Expand the **Account and limit** section.
1. Fill in the **Maximun allowable lifetime for personal access tokens (days)** field.
1. Click **Save changes**.
Once a lifetime for personal access tokens is set, GitLab will:
- Apply the lifetime for new personal access tokens, and require users to set an expiration date
and a date no later than the allowed lifetime.
- After three hours, revoke old tokens with no expiration date or with a lifetime longer than the
allowed lifetime. Three hours is given to allow administrators to change the allowed lifetime,
or remove it, before revocation takes place.
......@@ -4,45 +4,6 @@ module Gitlab
module Diff
module FileCollection
class MergeRequestDiff < MergeRequestDiffBase
include Gitlab::Utils::StrongMemoize
def diff_files
strong_memoize(:diff_files) do
diff_files = super
diff_files.each { |diff_file| cache.decorate(diff_file) }
diff_files
end
end
override :write_cache
def write_cache
cache.write_if_empty
end
override :clear_cache
def clear_cache
cache.clear
end
def cache_key
cache.key
end
def real_size
@merge_request_diff.real_size
end
private
def cache
@cache ||= if Feature.enabled?(:hset_redis_diff_caching, project)
Gitlab::Diff::HighlightCache.new(self)
else
Gitlab::Diff::DeprecatedHighlightCache.new(self)
end
end
end
end
end
......
......@@ -15,6 +15,44 @@ module Gitlab
diff_refs: merge_request_diff.diff_refs,
fallback_diff_refs: merge_request_diff.fallback_diff_refs)
end
def diff_files
strong_memoize(:diff_files) do
diff_files = super
diff_files.each { |diff_file| cache.decorate(diff_file) }
diff_files
end
end
override :write_cache
def write_cache
cache.write_if_empty
end
override :clear_cache
def clear_cache
cache.clear
end
def cache_key
cache.key
end
def real_size
@merge_request_diff.real_size
end
private
def cache
@cache ||= if Feature.enabled?(:hset_redis_diff_caching, project)
Gitlab::Diff::HighlightCache.new(self)
else
Gitlab::Diff::DeprecatedHighlightCache.new(self)
end
end
end
end
end
......
......@@ -42,7 +42,6 @@ module Gitlab
# Initialize gon.features with any flags that should be
# made globally available to the frontend
push_frontend_feature_flag(:suppress_ajax_navigation_errors, default_enabled: true)
push_frontend_feature_flag(:snippets_vue, default_enabled: false)
end
# Exposes the state of a feature flag to the frontend code.
......
......@@ -9128,6 +9128,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths"
msgstr ""
msgid "Hi %{username}!"
msgstr ""
msgid "Hide archived projects"
msgstr ""
......@@ -10274,6 +10277,9 @@ msgstr ""
msgid "Leave Admin Mode"
msgstr ""
msgid "Leave blank for no limit. Once set, existing personal access tokens may be revoked"
msgstr ""
msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
......@@ -10764,6 +10770,9 @@ msgstr ""
msgid "Max seats used"
msgstr ""
msgid "Maximum allowable lifetime for personal access token (days)"
msgstr ""
msgid "Maximum artifacts size (MB)"
msgstr ""
......@@ -10782,6 +10791,9 @@ msgstr ""
msgid "Maximum job timeout has a value which could not be accepted"
msgstr ""
msgid "Maximum lifetime allowable for Personal Access Tokens is active, your expire date must be set before %{maximum_allowable_date}."
msgstr ""
msgid "Maximum number of comments exceeded"
msgstr ""
......@@ -11985,6 +11997,9 @@ msgstr[1] ""
msgid "One or more groups that you don't have access to."
msgstr ""
msgid "One or more of you personal access tokens were revoked"
msgstr ""
msgid "One or more of your Bitbucket projects cannot be imported into GitLab directly because they use Subversion or Mercurial for version control, rather than Git."
msgstr ""
......@@ -17439,6 +17454,11 @@ msgstr ""
msgid "The following items will be exported:"
msgstr ""
msgid "The following personal access token: %{token_names} was revoked, because a new policy to expire personal access tokens were set."
msgid_plural "The following personal access tokens: %{token_names} were revoked, because a new policy to expire personal access tokens were set."
msgstr[0] ""
msgstr[1] ""
msgid "The fork relationship has been removed."
msgstr ""
......@@ -20114,6 +20134,12 @@ msgstr ""
msgid "You can create files directly in GitLab using one of the following options."
msgstr ""
msgid "You can create new ones at your %{pat_link_start}Personal Access Tokens%{pat_link_end} settings"
msgstr ""
msgid "You can create new ones at your Personal Access Tokens settings %{pat_link}"
msgstr ""
msgid "You can easily contribute to them by requesting to join these groups."
msgstr ""
......
......@@ -25,6 +25,16 @@ describe Projects::MergeRequests::DiffsController do
end
end
shared_examples 'cached diff collection' do
it 'ensures diff highlighting cache writing' do
expect_next_instance_of(Gitlab::Diff::HighlightCache) do |cache|
expect(cache).to receive(:write_if_empty).once
end
go
end
end
shared_examples 'persisted preferred diff view cookie' do
context 'with view param' do
before do
......@@ -112,6 +122,7 @@ describe Projects::MergeRequests::DiffsController do
end
it_behaves_like 'persisted preferred diff view cookie'
it_behaves_like 'cached diff collection'
end
describe 'GET diffs_metadata' do
......@@ -404,6 +415,7 @@ describe Projects::MergeRequests::DiffsController do
it_behaves_like 'forked project with submodules'
it_behaves_like 'persisted preferred diff view cookie'
it_behaves_like 'cached diff collection'
context 'diff unfolding' do
let!(:unfoldable_diff_note) do
......
......@@ -5,10 +5,6 @@ require 'spec_helper'
describe 'Internal Snippets', :js do
let(:internal_snippet) { create(:personal_snippet, :internal) }
before do
stub_feature_flags(snippets_vue: false)
end
describe 'normal user' do
before do
sign_in(create(:user))
......
......@@ -16,7 +16,6 @@ describe 'Comments on personal snippets', :js do
let!(:other_note) { create(:note_on_personal_snippet) }
before do
stub_feature_flags(snippets_vue: false)
sign_in user
visit snippet_path(snippet)
......
......@@ -6,7 +6,6 @@ describe 'Private Snippets', :js do
let(:user) { create(:user) }
before do
stub_feature_flags(snippets_vue: false)
sign_in(user)
end
......
......@@ -3,10 +3,6 @@
require 'spec_helper'
describe 'Public Snippets', :js do
before do
stub_feature_flags(snippets_vue: false)
end
it 'Unauthenticated user should see public snippets' do
public_snippet = create(:personal_snippet, :public)
......
......@@ -6,10 +6,6 @@ describe 'Snippet', :js do
let(:project) { create(:project, :repository) }
let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content) }
before do
stub_feature_flags(snippets_vue: false)
end
context 'Ruby file' do
let(:file_name) { 'popen.rb' }
let(:content) { project.repository.blob_at('master', 'files/ruby/popen.rb').data }
......
......@@ -7,7 +7,6 @@ describe 'User creates snippet', :js do
before do
stub_feature_flags(allow_possible_spam: false)
stub_feature_flags(snippets_vue: false)
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
Gitlab::CurrentSettings.update!(
......
......@@ -8,7 +8,6 @@ describe 'User creates snippet', :js do
let(:user) { create(:user) }
before do
stub_feature_flags(snippets_vue: false)
sign_in(user)
visit new_snippet_path
end
......
......@@ -10,8 +10,6 @@ describe 'User deletes snippet' do
before do
sign_in(user)
stub_feature_flags(snippets_vue: false)
visit snippet_path(snippet)
end
......
......@@ -12,7 +12,6 @@ describe 'User edits snippet', :js do
let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content, author: user) }
before do
stub_feature_flags(snippets_vue: false)
sign_in(user)
visit edit_snippet_path(snippet)
......
......@@ -6,38 +6,11 @@ describe 'Snippets' do
context 'when the project has snippets' do
let(:project) { create(:project, :public) }
let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.owner, project: project) }
before do
allow(Snippet).to receive(:default_per_page).and_return(1)
visit project_snippets_path(project)
visit snippets_path(username: project.owner.username)
end
it_behaves_like 'paginated snippets'
end
describe 'rendering engine' do
let_it_be(:snippet) { create(:personal_snippet, :public) }
let(:snippets_vue_feature_flag_enabled) { true }
before do
stub_feature_flags(snippets_vue: snippets_vue_feature_flag_enabled)
visit snippet_path(snippet)
end
it 'renders Vue application' do
expect(page).to have_selector('#js-snippet-view')
expect(page).not_to have_selector('.personal-snippets')
end
context 'when feature flag is disabled' do
let(:snippets_vue_feature_flag_enabled) { false }
it 'renders HAML application and not Vue' do
expect(page).not_to have_selector('#js-snippet-view')
expect(page).to have_selector('.personal-snippets')
end
end
end
end
import { createLocalVue, shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
import Embed from '~/monitoring/components/embed.vue';
import MonitorTimeSeriesChart from '~/monitoring/components/charts/time_series.vue';
import PanelType from 'ee_else_ce/monitoring/components/panel_type.vue';
import { TEST_HOST } from 'helpers/test_constants';
import { groups, initialState, metricsData, metricsWithData } from './mock_data';
......@@ -55,7 +55,7 @@ describe('Embed', () => {
it('shows an empty state when no metrics are present', () => {
expect(wrapper.find('.metrics-embed').exists()).toBe(true);
expect(wrapper.find(MonitorTimeSeriesChart).exists()).toBe(false);
expect(wrapper.find(PanelType).exists()).toBe(false);
});
});
......@@ -71,12 +71,12 @@ describe('Embed', () => {
it('shows a chart when metrics are present', () => {
wrapper.setProps({});
expect(wrapper.find('.metrics-embed').exists()).toBe(true);
expect(wrapper.find(MonitorTimeSeriesChart).exists()).toBe(true);
expect(wrapper.findAll(MonitorTimeSeriesChart).length).toBe(2);
expect(wrapper.find(PanelType).exists()).toBe(true);
expect(wrapper.findAll(PanelType).length).toBe(2);
});
it('includes groupId with dashboardUrl', () => {
expect(wrapper.find(MonitorTimeSeriesChart).props('groupId')).toBe(TEST_HOST);
expect(wrapper.find(PanelType).props('groupId')).toBe(TEST_HOST);
});
});
});
......@@ -102,6 +102,10 @@ describe('Panel Type component', () => {
expect(clipboardText()).toBe(exampleText);
});
it('includes a default group id', () => {
expect(panelType.vm.groupId).toBe('panel-type-chart');
});
});
describe('Anomaly Chart panel type', () => {
......
......@@ -123,4 +123,8 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiffBatch do
collection_default_args)
end
end
it_behaves_like 'cacheable diff collection' do
let(:cacheable_files_count) { batch_size }
end
end
......@@ -4,7 +4,8 @@ require 'spec_helper'
describe Gitlab::Diff::FileCollection::MergeRequestDiff do
let(:merge_request) { create(:merge_request) }
let(:subject) { described_class.new(merge_request.merge_request_diff, diff_options: nil) }
let(:diffable) { merge_request.merge_request_diff }
let(:subject) { described_class.new(diffable, diff_options: nil) }
let(:diff_files) { subject.diff_files }
describe '#diff_files' do
......@@ -52,6 +53,10 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiff do
let(:stub_path) { '.gitignore' }
end
it_behaves_like 'cacheable diff collection' do
let(:cacheable_files_count) { diffable.size.to_i }
end
it 'returns a valid instance of a DiffCollection' do
expect(diff_files).to be_a(Gitlab::Git::DiffCollection)
end
......
# frozen_string_literal: true
require 'spec_helper'
describe Ci::LegacyStagePresenter do
let(:legacy_stage) { create(:ci_stage) }
let(:presenter) { described_class.new(legacy_stage) }
let!(:build) { create(:ci_build, :tags, pipeline: legacy_stage.pipeline, stage: legacy_stage.name) }
let!(:retried_build) { create(:ci_build, :tags, :retried, pipeline: legacy_stage.pipeline, stage: legacy_stage.name) }
before do
create(:generic_commit_status, pipeline: legacy_stage.pipeline, stage: legacy_stage.name)
end
describe '#latest_ordered_statuses' do
subject(:latest_ordered_statuses) { presenter.latest_ordered_statuses }
it 'preloads build tags' do
expect(latest_ordered_statuses.second.association(:tags)).to be_loaded
end
end
describe '#retried_ordered_statuses' do
subject(:retried_ordered_statuses) { presenter.retried_ordered_statuses }
it 'preloads build tags' do
expect(retried_ordered_statuses.first.association(:tags)).to be_loaded
end
end
end
......@@ -57,3 +57,45 @@ shared_examples 'unfoldable diff' do
subject.unfold_diff_files([position])
end
end
shared_examples 'cacheable diff collection' do
let(:cache) { instance_double(Gitlab::Diff::HighlightCache) }
before do
expect(Gitlab::Diff::HighlightCache).to receive(:new).with(subject) { cache }
end
describe '#write_cache' do
it 'calls Gitlab::Diff::HighlightCache#write_if_empty' do
expect(cache).to receive(:write_if_empty).once
subject.write_cache
end
end
describe '#clear_cache' do
it 'calls Gitlab::Diff::HighlightCache#clear' do
expect(cache).to receive(:clear).once
subject.clear_cache
end
end
describe '#cache_key' do
it 'calls Gitlab::Diff::HighlightCache#key' do
expect(cache).to receive(:key).once
subject.cache_key
end
end
describe '#diff_files' do
it 'calls Gitlab::Diff::HighlightCache#decorate' do
expect(cache).to receive(:decorate)
.with(instance_of(Gitlab::Diff::File))
.exactly(cacheable_files_count).times
subject.diff_files
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment