Commit e20baee8 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 71c5863d
<!--Please answer the below questions to the best of your ability.-->
#### What's this issue all about? (Background and context)
#### What hypotheses and/or assumptions do you have?
#### What questions are you trying to answer?
#### What research methodology do you intend to use?
<!-- What needs to be answered to move work forward? If you have a completed Opportunity Canvas include a link.-->
#### What persona, persona segment, or customer type experiences the problem most acutely?
#### What business decisions will be made based on this information?
#### What, if any, relevant prior research already exists?
<!-- Have a look at our UXR_Insights repo: https://gitlab.com/gitlab-org/uxr_insights -->
#### Who will be leading the research?
#### What timescales do you have in mind for the research?
#### Relevant links (problem validation issue, design issue, script, prototype, notes, etc.)
<!-- #### TODO Checklist
Consider adding a checklist in order to keep track of what stage the research is up to. Some possible checklist templates are here:
https://about.gitlab.com/handbook/engineering/ux/ux-research-training/templates-resources-for-research-studies/#checklists
-->
/label ~"workflow::solution validation"
\ No newline at end of file
...@@ -204,7 +204,6 @@ Gitlab/DuplicateSpecLocation: ...@@ -204,7 +204,6 @@ Gitlab/DuplicateSpecLocation:
Exclude: Exclude:
- ee/spec/helpers/auth_helper_spec.rb - ee/spec/helpers/auth_helper_spec.rb
- ee/spec/lib/gitlab/gl_repository_spec.rb - ee/spec/lib/gitlab/gl_repository_spec.rb
- ee/spec/lib/gitlab/usage_data_spec.rb
- ee/spec/models/namespace_spec.rb - ee/spec/models/namespace_spec.rb
- ee/spec/models/note_spec.rb - ee/spec/models/note_spec.rb
- ee/spec/serializers/environment_entity_spec.rb - ee/spec/serializers/environment_entity_spec.rb
...@@ -215,7 +214,6 @@ Gitlab/DuplicateSpecLocation: ...@@ -215,7 +214,6 @@ Gitlab/DuplicateSpecLocation:
- ee/spec/services/system_hooks_service_spec.rb - ee/spec/services/system_hooks_service_spec.rb
- ee/spec/helpers/ee/auth_helper_spec.rb - ee/spec/helpers/ee/auth_helper_spec.rb
- ee/spec/lib/ee/gitlab/gl_repository_spec.rb - ee/spec/lib/ee/gitlab/gl_repository_spec.rb
- ee/spec/lib/ee/gitlab/usage_data_spec.rb
- ee/spec/models/ee/namespace_spec.rb - ee/spec/models/ee/namespace_spec.rb
- ee/spec/models/ee/note_spec.rb - ee/spec/models/ee/note_spec.rb
- ee/spec/serializers/ee/environment_entity_spec.rb - ee/spec/serializers/ee/environment_entity_spec.rb
...@@ -382,3 +380,6 @@ Style/FloatDivision: ...@@ -382,3 +380,6 @@ Style/FloatDivision:
Cop/BanCatchThrow: Cop/BanCatchThrow:
Enabled: true Enabled: true
Performance/ReadlinesEach:
Enabled: true
...@@ -8,13 +8,20 @@ import Flash from '../flash'; ...@@ -8,13 +8,20 @@ import Flash from '../flash';
import Poll from '../lib/utils/poll'; import Poll from '../lib/utils/poll';
import initSettingsPanels from '../settings_panels'; import initSettingsPanels from '../settings_panels';
import eventHub from './event_hub'; import eventHub from './event_hub';
import { APPLICATION_STATUS, INGRESS, INGRESS_DOMAIN_SUFFIX, CROSSPLANE } from './constants'; import {
APPLICATION_STATUS,
INGRESS,
INGRESS_DOMAIN_SUFFIX,
CROSSPLANE,
KNATIVE,
} from './constants';
import ClustersService from './services/clusters_service'; import ClustersService from './services/clusters_service';
import ClustersStore from './stores/clusters_store'; import ClustersStore from './stores/clusters_store';
import Applications from './components/applications.vue'; import Applications from './components/applications.vue';
import RemoveClusterConfirmation from './components/remove_cluster_confirmation.vue'; import RemoveClusterConfirmation from './components/remove_cluster_confirmation.vue';
import setupToggleButtons from '../toggle_buttons'; import setupToggleButtons from '../toggle_buttons';
import initProjectSelectDropdown from '~/project_select'; import initProjectSelectDropdown from '~/project_select';
import initServerlessSurveyBanner from '~/serverless/survey_banner';
const Environments = () => import('ee_component/clusters/components/environments.vue'); const Environments = () => import('ee_component/clusters/components/environments.vue');
...@@ -326,6 +333,10 @@ export default class Clusters { ...@@ -326,6 +333,10 @@ export default class Clusters {
this.store.state.applications[INGRESS], this.store.state.applications[INGRESS],
); );
} }
if (this.store.state.applications[KNATIVE]?.status === APPLICATION_STATUS.INSTALLED) {
initServerlessSurveyBanner();
}
} }
showToken() { showToken() {
......
import ServerlessBundle from '~/serverless/serverless_bundle'; import ServerlessBundle from '~/serverless/serverless_bundle';
import initServerlessSurveyBanner from '~/serverless/survey_banner';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
initServerlessSurveyBanner();
new ServerlessBundle(); // eslint-disable-line no-new new ServerlessBundle(); // eslint-disable-line no-new
}); });
import Vue from 'vue';
import { setUrlParams } from '~/lib/utils/url_utility';
import SurveyBanner from './survey_banner.vue';
let bannerInstance;
const SURVEY_URL_BASE = 'https://gitlab.fra1.qualtrics.com/jfe/form/SV_00PfofFfY9s8Shf';
export default function initServerlessSurveyBanner() {
const el = document.querySelector('.js-serverless-survey-banner');
if (el && !bannerInstance) {
const { userName, userEmail } = el.dataset;
// pre-populate survey fields
const surveyUrl = setUrlParams(
{
Q_PopulateResponse: JSON.stringify({
QID1: userEmail,
QID2: userName,
QID16: '1', // selects "yes" to "do you currently use GitLab?"
}),
},
SURVEY_URL_BASE,
);
bannerInstance = new Vue({
el,
render(createElement) {
return createElement(SurveyBanner, {
props: {
surveyUrl,
},
});
},
});
}
}
<script>
import Cookies from 'js-cookie';
import { parseBoolean } from '~/lib/utils/common_utils';
import { GlBanner } from '@gitlab/ui';
export default {
components: {
GlBanner,
},
props: {
surveyUrl: {
type: String,
required: true,
},
},
data() {
return {
visible: true,
};
},
created() {
if (parseBoolean(Cookies.get('hide_serverless_survey'))) {
this.visible = false;
}
},
methods: {
handleClose() {
Cookies.set('hide_serverless_survey', 'true', { expires: 365 * 10 });
this.visible = false;
},
},
};
</script>
<template>
<gl-banner
v-if="visible"
class="mt-4"
:title="s__('Serverless|Help shape the future of Serverless at GitLab')"
:button-text="s__('Serverless|Sign up for First Look')"
:button-link="surveyUrl"
@close="handleClose"
>
<p>
{{
s__(
'Serverless|We are continually striving to improve our Serverless functionality. As a Knative user, we would love to hear how we can make this experience better for you. Sign up for GitLab First Look today and we will be in touch shortly.',
)
}}
</p>
</gl-banner>
</template>
...@@ -8,7 +8,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -8,7 +8,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
# ApplicationSetting model uses Gitlab::ThreadMemoryCache for caching and the # ApplicationSetting model uses Gitlab::ThreadMemoryCache for caching and the
# cache might be stale immediately after an update. # cache might be stale immediately after an update.
# https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/30233 # https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/30233
before_action :set_application_setting before_action :set_application_setting, except: :integrations
before_action :whitelist_query_limiting, only: [:usage_data] before_action :whitelist_query_limiting, only: [:usage_data]
...@@ -29,12 +29,11 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -29,12 +29,11 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
def integrations def integrations
if Feature.enabled?(:instance_level_integrations) if Feature.enabled?(:instance_level_integrations)
# TODO: Update this with actual integrations @integrations = Service.find_or_initialize_instances.sort_by(&:title)
# To be fixed with https://gitlab.com/gitlab-org/gitlab/-/issues/199388 else
@integrations = [] set_application_setting
perform_update if submitted?
end end
perform_update if submitted?
end end
def update def update
......
...@@ -9,6 +9,11 @@ class Admin::ProjectsController < Admin::ApplicationController ...@@ -9,6 +9,11 @@ class Admin::ProjectsController < Admin::ApplicationController
def index def index
params[:sort] ||= 'latest_activity_desc' params[:sort] ||= 'latest_activity_desc'
@sort = params[:sort] @sort = params[:sort]
if params[:last_repository_check_failed].present? && params[:archived].nil?
params[:archived] = true
end
@projects = Admin::ProjectsFinder.new(params: params, current_user: current_user).execute @projects = Admin::ProjectsFinder.new(params: params, current_user: current_user).execute
respond_to do |format| respond_to do |format|
......
...@@ -6,7 +6,7 @@ class Admin::ServicesController < Admin::ApplicationController ...@@ -6,7 +6,7 @@ class Admin::ServicesController < Admin::ApplicationController
before_action :service, only: [:edit, :update] before_action :service, only: [:edit, :update]
def index def index
@services = Service.find_or_create_templates @services = Service.find_or_create_templates.sort_by(&:title)
end end
def edit def edit
......
...@@ -12,5 +12,8 @@ module Types ...@@ -12,5 +12,8 @@ module Types
field :id, GraphQL::ID_TYPE, null: false, field :id, GraphQL::ID_TYPE, null: false,
description: 'ID of the environment' description: 'ID of the environment'
field :state, GraphQL::STRING_TYPE, null: false,
description: 'State of the environment, for example: available/stopped'
end end
end end
...@@ -160,9 +160,7 @@ module BulkInsertSafe ...@@ -160,9 +160,7 @@ module BulkInsertSafe
attributes = {} attributes = {}
column_names.each do |name| column_names.each do |name|
value = item.read_attribute(name) attributes[name] = item.read_attribute(name)
value = item.type_for_attribute(name).serialize(value) # rubocop:disable Cop/ActiveRecordSerialize
attributes[name] = value
end end
_bulk_insert_reject_primary_key!(attributes, item.class.primary_key) _bulk_insert_reject_primary_key!(attributes, item.class.primary_key)
......
...@@ -47,6 +47,7 @@ class Service < ApplicationRecord ...@@ -47,6 +47,7 @@ class Service < ApplicationRecord
scope :without_defaults, -> { where(default: false) } scope :without_defaults, -> { where(default: false) }
scope :by_type, -> (type) { where(type: type) } scope :by_type, -> (type) { where(type: type) }
scope :templates, -> { where(template: true, type: available_services_types) } scope :templates, -> { where(template: true, type: available_services_types) }
scope :instances, -> { where(instance: true, type: available_services_types) }
scope :push_hooks, -> { where(push_events: true, active: true) } scope :push_hooks, -> { where(push_events: true, active: true) }
scope :tag_push_hooks, -> { where(tag_push_events: true, active: true) } scope :tag_push_hooks, -> { where(tag_push_events: true, active: true) }
...@@ -260,17 +261,16 @@ class Service < ApplicationRecord ...@@ -260,17 +261,16 @@ class Service < ApplicationRecord
self.category == :issue_tracker self.category == :issue_tracker
end end
# Find all service templates; if some of them do not exist, create them
# within a transaction to perform the lowest possible SQL queries.
def self.find_or_create_templates def self.find_or_create_templates
create_nonexistent_templates create_nonexistent_templates
templates templates
end end
private_class_method def self.create_nonexistent_templates private_class_method def self.create_nonexistent_templates
nonexistent_services = available_services_types - templates.map(&:type) nonexistent_services = list_nonexistent_services_for(templates)
return if nonexistent_services.empty? return if nonexistent_services.empty?
# Create within a transaction to perform the lowest possible SQL queries.
transaction do transaction do
nonexistent_services.each do |service_type| nonexistent_services.each do |service_type|
service_type.constantize.create(template: true) service_type.constantize.create(template: true)
...@@ -278,6 +278,20 @@ class Service < ApplicationRecord ...@@ -278,6 +278,20 @@ class Service < ApplicationRecord
end end
end end
def self.find_or_initialize_instances
instances + build_nonexistent_instances
end
private_class_method def self.build_nonexistent_instances
list_nonexistent_services_for(instances).map do |service_type|
service_type.constantize.new
end
end
private_class_method def self.list_nonexistent_services_for(scope)
available_services_types - scope.map(&:type)
end
def self.available_services_names def self.available_services_names
service_names = %w[ service_names = %w[
alerts alerts
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
%th Service %th Service
%th Description %th Description
%th Last edit %th Last edit
- @services.sort_by(&:title).each do |service| - @services.each do |service|
%tr %tr
%td %td
= boolean_to_icon service.activated? = boolean_to_icon service.activated?
......
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
.js-cluster-application-notice .js-cluster-application-notice
.flash-container .flash-container
.js-serverless-survey-banner{ data: { user_name: current_user.name, user_email: current_user.email } }
%h4= @cluster.name %h4= @cluster.name
= render 'banner' = render 'banner'
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
help_path: help_page_path('user/project/clusters/serverless/index') } } help_path: help_page_path('user/project/clusters/serverless/index') } }
%div{ class: [('limit-container-width' unless fluid_layout)] } %div{ class: [('limit-container-width' unless fluid_layout)] }
.js-serverless-survey-banner{ data: { user_name: current_user.name, user_email: current_user.email } }
.js-serverless-functions-notice .js-serverless-functions-notice
.flash-container .flash-container
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
%th{ role: 'columnheader', scope: 'col', 'aria-colindex': 4 }= _('Last updated') %th{ role: 'columnheader', scope: 'col', 'aria-colindex': 4 }= _('Last updated')
%tbody{ role: 'rowgroup' } %tbody{ role: 'rowgroup' }
- @integrations&.each do |integration| - @integrations.each do |integration|
%tr{ role: 'row' } %tr{ role: 'row' }
%td{ role: 'cell', 'aria-colindex': 1 } %td{ role: 'cell', 'aria-colindex': 1 }
= boolean_to_icon integration.activated? = boolean_to_icon integration.activated?
......
---
title: Fix archived corrupted projects not displaying in admin
merge_request: 25171
author: erickcspice
type: fixed
---
title: Provide link to a survey for Knative users
merge_request: 23025
author:
type: other
# frozen_string_literal: true
# This fix is needed to properly support
# columns that perform data mutation to a SQL datatype
# ex. would be `jsonb` and `enum`
#
# This is covered by tests in `BulkInsertSafe`
# that validates handling of different data types
if Rails.gem_version > Gem::Version.new("6.0.2")
raise Gem::DependencyError,
"Remove patch once the https://github.com/rails/rails/pull/38763 is included"
end
module ActiveRecordInsertAllBuilderMixin
def extract_types_from_columns_on(table_name, keys:)
columns = connection.schema_cache.columns_hash(table_name)
unknown_column = (keys - columns.keys).first
raise UnknownAttributeError.new(model.new, unknown_column) if unknown_column
keys.index_with { |key| model.type_for_attribute(key) }
end
end
ActiveRecord::InsertAll::Builder.prepend(ActiveRecordInsertAllBuilderMixin)
...@@ -2,19 +2,28 @@ ...@@ -2,19 +2,28 @@
require_relative File.expand_path('../../lib/gitlab/danger/commit_linter', __dir__) require_relative File.expand_path('../../lib/gitlab/danger/commit_linter', __dir__)
URL_GIT_COMMIT = "https://chris.beams.io/posts/git-commit/" COMMIT_MESSAGE_GUIDELINES = "https://docs.gitlab.com/ee/development/contributing/merge_request_workflow.html#commit-messages-guidelines"
MORE_INFO = "For more information, take a look at our [Commit message guidelines](#{COMMIT_MESSAGE_GUIDELINES})."
THE_DANGER_JOB_TEXT = "the `danger-review` job"
MAX_COMMITS_COUNT = 10 MAX_COMMITS_COUNT = 10
def gitlab_danger def gitlab_danger
@gitlab_danger ||= GitlabDanger.new(helper.gitlab_helper) @gitlab_danger ||= GitlabDanger.new(helper.gitlab_helper)
end end
def fail_commit(commit, message) def fail_commit(commit, message, more_info: true)
self.fail("#{commit.sha}: #{message}") self.fail(build_message(commit, message, more_info: more_info))
end end
def warn_commit(commit, message) def warn_commit(commit, message, more_info: true)
self.warn("#{commit.sha}: #{message}") self.warn(build_message(commit, message, more_info: more_info))
end
def build_message(commit, message, more_info: true)
[message].tap do |full_message|
full_message << ". #{MORE_INFO}" if more_info
full_message.unshift("#{commit.sha}: ") if commit.sha
end.join
end end
def squash_mr? def squash_mr?
...@@ -25,6 +34,10 @@ def wip_mr? ...@@ -25,6 +34,10 @@ def wip_mr?
gitlab_danger.ci? ? gitlab.mr_json['work_in_progress'] : false gitlab_danger.ci? ? gitlab.mr_json['work_in_progress'] : false
end end
def danger_job_link
gitlab_danger.ci? ? "[#{THE_DANGER_JOB_TEXT}](#{ENV['CI_JOB_URL']})" : THE_DANGER_JOB_TEXT
end
# Perform various checks against commits. We're not using # Perform various checks against commits. We're not using
# https://github.com/jonallured/danger-commit_lint because its output is not # https://github.com/jonallured/danger-commit_lint because its output is not
# very helpful, and it doesn't offer the means of ignoring merge commits. # very helpful, and it doesn't offer the means of ignoring merge commits.
...@@ -42,11 +55,11 @@ def lint_commit(commit) ...@@ -42,11 +55,11 @@ def lint_commit(commit)
return linter if linter.fixup? && squash_mr? return linter if linter.fixup? && squash_mr?
if linter.fixup? if linter.fixup?
msg = 'Squash or fixup commits must be squashed before merge, or enable squash merge option' msg = "Squash or fixup commits must be squashed before merge, or enable squash merge option and re-run #{danger_job_link}."
if wip_mr? || squash_mr? if wip_mr? || squash_mr?
warn_commit(commit, msg) warn_commit(commit, msg, more_info: false)
else else
fail_commit(commit, msg) fail_commit(commit, msg, more_info: false)
end end
# Makes no sense to process other rules for fixup commits, they trigger just more noise # Makes no sense to process other rules for fixup commits, they trigger just more noise
...@@ -56,7 +69,7 @@ def lint_commit(commit) ...@@ -56,7 +69,7 @@ def lint_commit(commit)
# Fail if a suggestion commit is used and squash is not enabled # Fail if a suggestion commit is used and squash is not enabled
if linter.suggestion? if linter.suggestion?
unless squash_mr? unless squash_mr?
fail_commit(commit, "If you are applying suggestions, enable squash in the merge request and re-run the `danger-review` job") fail_commit(commit, "If you are applying suggestions, enable squash in the merge request and re-run #{danger_job_link}.", more_info: false)
end end
return linter return linter
...@@ -93,18 +106,12 @@ def lint_commits(commits) ...@@ -93,18 +106,12 @@ def lint_commits(commits)
if multi_line_commit_linter && multi_line_commit_linter.failed? if multi_line_commit_linter && multi_line_commit_linter.failed?
warn_or_fail_commits(multi_line_commit_linter) warn_or_fail_commits(multi_line_commit_linter)
fail_message('The commit message that will be used in the squash commit does not meet our Git commit message standards.')
else else
title_linter = lint_mr_title(gitlab.mr_json['title']) title_linter = lint_mr_title(gitlab.mr_json['title'])
if title_linter.failed? if title_linter.failed?
warn_or_fail_commits(title_linter) warn_or_fail_commits(title_linter)
fail_message('The merge request title that will be used in the squash commit does not meet our Git commit message standards.')
end end
end end
else
if failed_commit_linters.any?
fail_message('One or more commit messages do not meet our Git commit message standards.')
end
end end
end end
...@@ -123,40 +130,4 @@ def warn_or_fail_commits(failed_linters, default_to_fail: true) ...@@ -123,40 +130,4 @@ def warn_or_fail_commits(failed_linters, default_to_fail: true)
end end
end end
def fail_message(intro)
markdown(<<~MARKDOWN)
## Commit message standards
#{intro}
For more information on how to write a good commit message, take a look at
[How to Write a Git Commit Message](#{URL_GIT_COMMIT}).
Here is an example of a good commit message:
Reject ruby interpolation in externalized strings
When using ruby interpolation in externalized strings, they can't be
detected. Which means they will never be presented to be translated.
To mix variables into translations we need to use `sprintf`
instead.
Instead of:
_("Hello \#{subject}")
Use:
_("Hello %{subject}") % { subject: 'world' }
This is an example of a bad commit message:
updated README.md
This commit message is bad because although it tells us that README.md is
updated, it doesn't tell us why or how it was updated.
MARKDOWN
end
lint_commits(git.commits) lint_commits(git.commits)
...@@ -96,7 +96,5 @@ they will receive a `Connection failed` message. ...@@ -96,7 +96,5 @@ they will receive a `Connection failed` message.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8413) in GitLab 8.17. > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8413) in GitLab 8.17.
Terminal sessions use long-lived connections; by default, these may last Terminal sessions, by default, do not expire.
forever. You can configure a maximum session time in the Admin Area of your You can limit terminal session lifetime in your GitLab instance. To do so, navigate to **{admin}** [**Admin Area > Settings > Web terminal**](../../user/admin_area/settings/index.md#general), and set a `max session time`.
GitLab instance if you find this undesirable from a scalability or security
point of view.
...@@ -21,10 +21,7 @@ This project will be used for self monitoring your GitLab instance. ...@@ -21,10 +21,7 @@ This project will be used for self monitoring your GitLab instance.
1. Navigate to **Admin Area > Settings > Metrics and profiling**, and expand the **Self monitoring** section. 1. Navigate to **Admin Area > Settings > Metrics and profiling**, and expand the **Self monitoring** section.
1. Toggle the **Create Project** button on. 1. Toggle the **Create Project** button on.
1. It can take a few seconds for the project to be created. After the project is 1. Once your GitLab instance creates the project, you'll see a link to the project in the text above the **Create Project** toggle. You can also find it under **Projects > Your projects**.
created, GitLab displays a message with a link to the project. The project
will also be linked in the help text above the **Create Project** button. You can also
find the project under **Projects > Your projects**.
## Deleting the self monitoring project ## Deleting the self monitoring project
......
...@@ -1869,6 +1869,11 @@ type Environment { ...@@ -1869,6 +1869,11 @@ type Environment {
Human-readable name of the environment Human-readable name of the environment
""" """
name: String! name: String!
"""
State of the environment, for example: available/stopped
"""
state: String!
} }
""" """
......
...@@ -5530,6 +5530,24 @@ ...@@ -5530,6 +5530,24 @@
"description": "Human-readable name of the environment", "description": "Human-readable name of the environment",
"args": [ "args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "state",
"description": "State of the environment, for example: available/stopped",
"args": [
], ],
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
......
...@@ -318,6 +318,7 @@ Describes where code is deployed for a project ...@@ -318,6 +318,7 @@ Describes where code is deployed for a project
| --- | ---- | ---------- | | --- | ---- | ---------- |
| `id` | ID! | ID of the environment | | `id` | ID! | ID of the environment |
| `name` | String! | Human-readable name of the environment | | `name` | String! | Human-readable name of the environment |
| `state` | String! | State of the environment, for example: available/stopped |
## Epic ## Epic
......
...@@ -73,6 +73,10 @@ GET /groups/:id/packages ...@@ -73,6 +73,10 @@ GET /groups/:id/packages
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/packages?exclude_subgroups=true curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/packages?exclude_subgroups=true
``` ```
CAUTION: **Deprecation**
> The `build_info` attribute in the response is deprecated in favour of `pipeline`.
> Introduced [GitLab 12.10](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28040).
Example response: Example response:
```json ```json
...@@ -87,15 +91,17 @@ Example response: ...@@ -87,15 +91,17 @@ Example response:
"delete_api_path": "/namespace1/project1/-/packages/1" "delete_api_path": "/namespace1/project1/-/packages/1"
}, },
"created_at": "2019-11-27T03:37:38.711Z", "created_at": "2019-11-27T03:37:38.711Z",
"build_info": { "pipeline": {
"pipeline": { "id": 123,
"id": 123, "status": "pending",
"status": "pending", "ref": "new-pipeline",
"ref": "new-pipeline", "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
"sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", "web_url": "https://example.com/foo/bar/pipelines/47",
"web_url": "https://example.com/foo/bar/pipelines/47", "created_at": "2016-08-11T11:28:34.085Z",
"created_at": "2016-08-11T11:28:34.085Z", "updated_at": "2016-08-11T11:32:35.169Z",
"updated_at": "2016-08-11T11:32:35.169Z", "user": {
"name": "Administrator",
"avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon"
} }
} }
}, },
...@@ -109,15 +115,17 @@ Example response: ...@@ -109,15 +115,17 @@ Example response:
"delete_api_path": "/namespace1/project1/-/packages/1" "delete_api_path": "/namespace1/project1/-/packages/1"
}, },
"created_at": "2019-11-27T03:37:38.711Z", "created_at": "2019-11-27T03:37:38.711Z",
"build_info": { "pipeline": {
"pipeline": { "id": 123,
"id": 123, "status": "pending",
"status": "pending", "ref": "new-pipeline",
"ref": "new-pipeline", "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
"sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", "web_url": "https://example.com/foo/bar/pipelines/47",
"web_url": "https://example.com/foo/bar/pipelines/47", "created_at": "2016-08-11T11:28:34.085Z",
"created_at": "2016-08-11T11:28:34.085Z", "updated_at": "2016-08-11T11:32:35.169Z",
"updated_at": "2016-08-11T11:32:35.169Z", "user": {
"name": "Administrator",
"avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon"
} }
} }
} }
...@@ -150,6 +158,10 @@ GET /projects/:id/packages/:package_id ...@@ -150,6 +158,10 @@ GET /projects/:id/packages/:package_id
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/packages/:package_id curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/packages/:package_id
``` ```
CAUTION: **Deprecation**
> The `build_info` attribute in the response is deprecated in favour of `pipeline`.
> Introduced [GitLab 12.10](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28040).
Example response: Example response:
```json ```json
...@@ -163,15 +175,17 @@ Example response: ...@@ -163,15 +175,17 @@ Example response:
"delete_api_path": "/namespace1/project1/-/packages/1" "delete_api_path": "/namespace1/project1/-/packages/1"
}, },
"created_at": "2019-11-27T03:37:38.711Z", "created_at": "2019-11-27T03:37:38.711Z",
"build_info": { "pipeline": {
"pipeline": { "id": 123,
"id": 123, "status": "pending",
"status": "pending", "ref": "new-pipeline",
"ref": "new-pipeline", "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
"sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a", "web_url": "https://example.com/foo/bar/pipelines/47",
"web_url": "https://example.com/foo/bar/pipelines/47", "created_at": "2016-08-11T11:28:34.085Z",
"created_at": "2016-08-11T11:28:34.085Z", "updated_at": "2016-08-11T11:32:35.169Z",
"updated_at": "2016-08-11T11:32:35.169Z", "user": {
"name": "Administrator",
"avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon"
} }
} }
} }
......
...@@ -81,7 +81,7 @@ Complementary reads: ...@@ -81,7 +81,7 @@ Complementary reads:
- [Working with Merge Request diffs](diffs.md) - [Working with Merge Request diffs](diffs.md)
- [Kubernetes integration guidelines](kubernetes.md) - [Kubernetes integration guidelines](kubernetes.md)
- [Permissions](permissions.md) - [Permissions](permissions.md)
- [Prometheus metrics](prometheus_metrics.md) - [Prometheus](prometheus.md)
- [Guidelines for reusing abstractions](reusing_abstractions.md) - [Guidelines for reusing abstractions](reusing_abstractions.md)
- [DeclarativePolicy framework](policies.md) - [DeclarativePolicy framework](policies.md)
- [How Git object deduplication works in GitLab](git_object_deduplication.md) - [How Git object deduplication works in GitLab](git_object_deduplication.md)
......
# Working with Prometheus
For more information on working with [Prometheus metrics](prometheus_metrics.md), see
the documentation.
## Access the UI of a Prometheus managed application in Kubernetes
You can connect directly to Prometheus, and view the Prometheus user interface, when
using a Prometheus managed application in Kubernetes:
1. Find the name of the Prometheus pod in the user interface of your Kubernetes
provider, such as GKE, or by running the following `kubectl` command in your
terminal:
```shell
kubectl get pods -n gitlab-managed-apps | grep 'prometheus-prometheus-server'
```
The command should return a result like the following example, where
`prometheus-prometheus-server-55b4bd64c9-dpc6b` is the name of the Prometheus pod:
```plaintext
gitlab-managed-apps prometheus-prometheus-server-55b4bd64c9-dpc6b 2/2 Running 0 71d
```
1. Run a `kubectl port-forward` command. In the following example, `9090` is the
Prometheus server's listening port:
```shell
kubectl port-forward prometheus-prometheus-server-55b4bd64c9-dpc6b 9090:9090 -n gitlab-managed-apps
```
The `port-forward` command forwards all requests sent to your system's `9090` port
to the `9090` port of the Prometheus pod. If the `9090` port on your system is used
by another application, you can change the port number before the colon to your
desired port. For example, to forward port `8080` of your local system, change the
command to:
```shell
kubectl port-forward prometheus-prometheus-server-55b4bd64c9-dpc6b 8080:9090 -n gitlab-managed-apps
```
1. Open `localhost:9090` in your browser to display the Prometheus user interface.
...@@ -122,6 +122,19 @@ RDS instances as well: ...@@ -122,6 +122,19 @@ RDS instances as well:
| `gitlab-public-10.0.2.0` | public | `us-west-2b` | `10.0.2.0` | | `gitlab-public-10.0.2.0` | public | `us-west-2b` | `10.0.2.0` |
| `gitlab-private-10.0.3.0` | private | `us-west-2b` | `10.0.3.0` | | `gitlab-private-10.0.3.0` | private | `us-west-2b` | `10.0.3.0` |
### Create NAT Gateways
Instances deployed in our private subnets need to connect to the internet for updates, but should not be reachable from the public internet. To achieve this, we'll make use of [NAT Gateways](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html) deployed in each of our public subnets:
1. Navigate to the VPC dashboard and click on **NAT Gateways** in the left menu bar.
1. Click **Create NAT Gateway** and complete the following:
1. **Subnet**: Select `gitlab-public-10.0.0.0` from the dropdown.
1. **Elastic IP Allocation ID**: Enter an existing Elastic IP or click **Allocate Elastic IP address** to allocate a new IP to your NAT gateway.
1. Add tags if needed.
1. Click **Create NAT Gateway**.
Create a second NAT gateway but this time place it in the second public subnet, `gitlab-public-10.0.2.0`.
### Route Table ### Route Table
Up to now all our subnets are private. We need to create a Route Table Up to now all our subnets are private. We need to create a Route Table
......
...@@ -16,3 +16,4 @@ comments: false ...@@ -16,3 +16,4 @@ comments: false
- [Rebuild authorized_keys file](../administration/raketasks/maintenance.md#rebuild-authorized_keys-file) task for administrators - [Rebuild authorized_keys file](../administration/raketasks/maintenance.md#rebuild-authorized_keys-file) task for administrators
- [Uploads Migrate](../administration/raketasks/uploads/migrate.md) - [Uploads Migrate](../administration/raketasks/uploads/migrate.md)
- [Uploads Sanitize](../administration/raketasks/uploads/sanitize.md) - [Uploads Sanitize](../administration/raketasks/uploads/sanitize.md)
- [Importing large GitLab project exports](../development/import_project.md#importing-via-a-rake-task)
...@@ -535,18 +535,14 @@ in the first place, and thus not realize that it needs to re-apply the old confi ...@@ -535,18 +535,14 @@ in the first place, and thus not realize that it needs to re-apply the old confi
> Introduced in [GitLab Ultimate][ee] 10.4. > Introduced in [GitLab Ultimate][ee] 10.4.
This is an optional step, since it requires a [review app](#auto-review-apps).
If that requirement is not met, the job will be silently skipped.
Dynamic Application Security Testing (DAST) uses the Dynamic Application Security Testing (DAST) uses the
popular open source tool [OWASP ZAProxy](https://github.com/zaproxy/zaproxy) popular open source tool [OWASP ZAProxy](https://github.com/zaproxy/zaproxy)
to perform an analysis on the current code and checks for potential security to perform an analysis on the current code and checks for potential security
issues. The Auto DAST stage will be skipped on licenses other than Ultimate. issues. The Auto DAST stage will be skipped on licenses other than Ultimate.
Once the report is created, it's uploaded as an artifact which you can Once the DAST scan is complete, any security warnings are shown
later download and check out. on the [Security Dashboard](../../user/application_security/security_dashboard/index.md)
and the Merge Request Widget. Read how
Any security warnings are also shown in the merge request widget. Read how
[DAST works](../../user/application_security/dast/index.md). [DAST works](../../user/application_security/dast/index.md).
On your default branch, DAST scans an app deployed specifically for that purpose. On your default branch, DAST scans an app deployed specifically for that purpose.
......
...@@ -4,35 +4,110 @@ type: index ...@@ -4,35 +4,110 @@ type: index
# Admin Area settings **(CORE ONLY)** # Admin Area settings **(CORE ONLY)**
In the Admin Area **Settings** page, you can find various options for your GitLab As an administrator of a GitLab self-managed instance, you can manage the behavior of your deployment. To do so, select **{admin}** **Admin Area > Settings**.
instance like sign-up restrictions, account limits and quota, metrics, etc.
Navigate to it by going to **Admin Area > Settings**. Some of the settings
include:
- [Account and limit settings](account_and_limit_settings.md) **(STARTER)**
- [Continuous Integration and Deployment](continuous_integration.md)
- [Email](email.md)
- [Sign up restrictions](sign_up_restrictions.md)
- [Sign in restrictions](sign_in_restrictions.md)
- [Terms](terms.md)
- [Third party offers](third_party_offers.md)
- [Usage statistics](usage_statistics.md)
- [Visibility and access controls](visibility_and_access_controls.md)
- [User and IP rate limits](user_and_ip_rate_limits.md)
- [Custom templates repository](instance_template_repository.md) **(PREMIUM)**
- [Protected paths](protected_paths.md) **(CORE ONLY)**
- [Help messages for the `/help` page and the login page](help_page.md)
- [Push event activities limit and bulk push events](push_event_activities_limit.md)
- [Gitaly timeouts](gitaly_timeouts.md)
NOTE: **Note:** The admin area is not accessible on GitLab.com, and settings can only be changed by the
You can change the [first day of the week](../../profile/preferences.md) for the entire GitLab instance GitLab.com administrators. See the [GitLab.com settings](../../gitlab_com/index.md)
in the **Localization** section of **Admin Area > Settings > Preferences**. documentation for all current settings and limits on the GitLab.com instance.
## General
Access the default page for admin area settings by navigating to
**{admin}** **Admin Area > Settings > General**:
| Option | Description |
| ------ | ----------- |
| [Visibility and access controls](visibility_and_access_controls.md) | Set default and restrict visibility levels. Configure import sources and Git access protocol. |
| [Account and limit](account_and_limit_settings.md) **(STARTER)** | Set projects and maximum size limits, session duration, user options, and check feature availability for namespace plan. |
| [Diff limits](../diff_limits.md) | Diff content limits. |
| [Sign-up restrictions](sign_up_restrictions.md) | Configure the way a user creates a new account. |
| [Sign in restrictions](sign_in_restrictions.md) | Set requirements for a user to sign-in. Enable mandatory two-factor authentication. |
| [Terms of Service and Privacy Policy](terms.md) | Include a Terms of Service agreement and Privacy Policy that all users must accept. |
| [External Authentication](external_authorization.md#configuration) | External Classification Policy Authorization |
| [Web terminal](../../../administration/integration/terminal.md#limiting-websocket-connection-time) | Set max session time for web terminal. |
| [Web IDE](../../project/web_ide/index.md#enabling-client-side-evaluation) | Manage Web IDE Features. |
## Integrations
| Option | Description |
| ------ | ----------- |
| [Elasticsearch](../../../integration/elasticsearch.md#enabling-elasticsearch) | Elasticsearch integration. Elasticsearch AWS IAM. |
| [PlantUML](../../../administration/integration/plantuml.md#gitlab) | Allow rendering of PlantUML diagrams in Asciidoc documents. |
| [Slack application](../../../user/project/integrations/gitlab_slack_application.md#configuration) **(FREE ONLY)** | Slack integration allows you to interact with GitLab via slash commands in a chat window. This option is only available on GitLab.com, though it may be [available for self-managed instances in the future](https://gitlab.com/gitlab-org/gitlab/-/issues/28164). |
| [Third party offers](third_party_offers.md) | Control the display of third party offers. |
| [Snowplow](../../../telemetry/index.md#enabling-tracking) | Configure the Snowplow integration. |
| [Amazon EKS](../../project/clusters/add_remove_clusters.md#additional-requirements-for-self-managed-instances-core-only) | Amazon EKS integration allows you to provision EKS clusters from GitLab. |
## Repository
| Option | Description |
| ------ | ----------- |
| [Repository mirror](visibility_and_access_controls.md#allow-mirrors-to-be-set-up-for-projects) | Configure repository mirroring. |
| [Repository storage](../../../administration/repository_storage_types.md#how-to-migrate-to-hashed-storage) | Configure storage path settings. |
| Repository maintenance | ([Repository checks](../../../administration/repository_checks.md) and [Housekeeping](../../../administration/housekeeping.md)). Configure automatic Git checks and housekeeping on repositories. |
| [Repository static objects](../../../administration/static_objects_external_storage.md) | Serve repository static objects (e.g. archives, blobs, ...) from an external storage (e.g. a CDN). |
## Templates **(PREMIUM ONLY)**
| Option | Description |
| ------ | ----------- |
| [Templates](instance_template_repository.md#configuration) | Set instance-wide template repository. |
| [Custom project templates](../custom_project_templates.md) | Select the custom project template source group. |
## CI/CD
## GitLab.com Admin Area settings | Option | Description |
| ------ | ----------- |
| [Continuous Integration and Deployment](continuous_integration.md) | Auto DevOps, runners and job artifacts. |
| [Required pipeline configuration](continuous_integration.md#required-pipeline-configuration-premium-only) **(PREMIUM ONLY)** | Set an instance-wide auto included [pipeline configuration](../../../ci/yaml/README.md). This pipeline configuration will be run after the project's own configuration. |
| [Package Registry](continuous_integration.md#package-registry-configuration-premium-only) **(PREMIUM ONLY)**| Settings related to the use and experience of using GitLab's Package Registry. |
Most of the settings under the Admin Area change the behavior of the whole ## Reporting
GitLab instance. For GitLab.com, the admin settings are available only for the
GitLab.com administrators, and the parameters can be found on the | Option | Description |
[GitLab.com settings](../../gitlab_com/index.md) documentation. | ------ | ----------- |
| [Spam and Anti-bot Protection](../../../integration/recaptcha.md) | Enable reCAPTCHA or Akismet and set IP limits. For reCAPTCHA, we currently only support [v2](https://developers.google.com/recaptcha/docs/versions). |
| [Abuse reports](../abuse_reports.md) | Set notification email for abuse reports. |
## Metrics and profiling
| Option | Description |
| ------ | ----------- |
| [Metrics - Influx](../../../administration/monitoring/performance/gitlab_configuration.md) | Enable and configure InfluxDB metrics. |
| [Metrics - Prometheus](../../../administration/monitoring/prometheus/gitlab_metrics.md) | Enable and configure Prometheus metrics. |
| [Metrics - Grafana](../../../administration/monitoring/performance/grafana_configuration.md#integration-with-gitlab-ui) | Enable and configure Grafana. |
| [Profiling - Performance bar](../../../administration/monitoring/performance/performance_bar.md#enable-the-performance-bar-via-the-admin-panel) | Enable access to the Performance Bar for a given group. |
| [Self monitoring](../../../administration/monitoring/gitlab_self_monitoring_project/index.md#creating-the-self-monitoring-project) | Enable or disable instance self monitoring. |
| [Usage statistics](usage_statistics.md) | Enable or disable version check and usage ping. |
| [Pseudonymizer data collection](../../../administration/pseudonymizer.md) **(ULTIMATE)** | Enable or disable the Pseudonymizer data collection. |
## Network
| Option | Description |
| ------ | ----------- |
| Performance optimization | [Write to "authorized_keys" file](../../../administration/operations/fast_ssh_key_lookup.md#setting-up-fast-lookup-via-gitlab-shell) and [Push event activities limit and bulk push events](push_event_activities_limit.md). Various settings that affect GitLab performance. |
| [User and IP rate limits](user_and_ip_rate_limits.md) | Configure limits for web and API requests. |
| [Outbound requests](../../../security/webhooks.md) | Allow requests to the local network from hooks and services. |
| [Protected Paths](protected_paths.md) | Configure paths to be protected by Rack Attack. |
| [Incident Management](../../incident_management/index.md) Limits | Configure limits on the number of inbound alerts able to be sent to a project. |
## Geo
| Option | Description |
| ------ | ----------- |
| Geo | Geo allows you to replicate your GitLab instance to other geographical locations. Redirects to **{admin}** **Admin Area >** **{location-dot}** **Geo >** **{settings}** **Settings**, and will no longer be available at **{admin}** **Admin Area >** **{settings}** **Settings >** **{location-dot}** **Geo** in [GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/36896). |
## Preferences
| Option | Description |
| ------ | ----------- |
| [Email](email.md) | Various email settings. |
| [Help page](../../../customization/help_message.md) | Help page text and support page url. |
| [Pages](../../../administration/pages/index.md#custom-domain-verification) | Size and domain settings for static websites |
| [Real-time features](../../../administration/polling.md) | Change this value to influence how frequently the GitLab UI polls for updates. |
| [Gitaly timeouts](gitaly_timeouts.md) | Configure Gitaly timeouts. |
| Localization | [Default first day of the week](../../profile/preferences.md) and [Time tracking](../../project/time_tracking.md#limit-displayed-units-to-hours-core-only). |
NOTE: **Note:**
You can change the [Default first day of the week](../../profile/preferences.md) for the entire GitLab instance
in the **Localization** section of **Admin Area > Settings > Preferences**.
# Analytics workspace # Analytics
## Analytics workspace
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12077) in GitLab 12.2. > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12077) in GitLab 12.2.
...@@ -6,27 +8,30 @@ The Analytics workspace will make it possible to aggregate analytics across ...@@ -6,27 +8,30 @@ The Analytics workspace will make it possible to aggregate analytics across
GitLab, so that users can view information across multiple projects and groups GitLab, so that users can view information across multiple projects and groups
in one place. in one place.
To access the centralized analytics workspace, enable at least To access the Analytics workspace, click on **More > Analytics** in the top navigation bar.
[one of the features](#available-analytics) under the workspace.
Once enabled, click on **Analytics** from the top navigation bar. ## Group-level analytics
## Available analytics > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/195979) in GitLab 12.8.
From the centralized analytics workspace, the following analytics are available: The following analytics features are available at the group level:
- [Code Review Analytics](code_review_analytics.md). **(STARTER)** - [Contribution](../group/contribution_analytics/index.md). **(STARTER)**
- [Value Stream Analytics](value_stream_analytics.md), enabled with the `cycle_analytics` - [Insights](../group/insights/index.md). **(ULTIMATE)**
- [Issues](../group/issues_analytics/index.md). **(PREMIUM)**
- [Productivity](productivity_analytics.md), enabled with the `productivity_analytics`
[feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-in-development). **(PREMIUM)** [feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-in-development). **(PREMIUM)**
- [Productivity Analytics](productivity_analytics.md), enabled with the `productivity_analytics` - [Value Stream](value_stream_analytics.md), enabled with the `cycle_analytics`
[feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-in-development). **(PREMIUM)** [feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-in-development). **(PREMIUM)**
NOTE: **Note:** ## Project-level analytics
Project-level Value Stream Analytics are still available at a project's **Project > Value Stream Analytics**.
## Other analytics tools
In addition to the tools available in the Analytics workspace, GitLab provides: The following analytics features are available at the project level:
- [Contribution analytics](../group/contribution_analytics/index.md). **(STARTER)** - [CI/CD](../../ci/pipelines/index.md#pipeline-success-and-duration-charts). **(STARTER)**
- [Issue analytics](../group/issues_analytics/index.md). **(PREMIUM)** - [Code Review](code_review_analytics.md). **(STARTER)**
- [Insights](../group/insights/index.md). **(ULTIMATE)**
- [Issues](../group/issues_analytics/index.md). **(PREMIUM)**
- Repository. **(STARTER)**
- [Value Stream](value_stream_analytics.md), enabled with the `cycle_analytics`
[feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-in-development). **(STARTER)**
...@@ -2,48 +2,62 @@ ...@@ -2,48 +2,62 @@
type: reference, howto type: reference, howto
--- ---
# Offline deployments # Air-gapped (or offline) environment deployments
This document describes how to operate Secure scanners offline. It is possible to run most of the GitLab security scanners when not
connected to the internet.
## Overview This document describes how to operate Secure scanners in an air-gapped or offline envionment. These instructions also apply to
self-managed installations that are secured, have security policies (e.g., firewall policies), or otherwise restricted from
accessing the full internet. These instructions are designed for physically disconnected networks,
but can also be followed in these other use cases.
It is possible to run most of the GitLab security scanners when not ## Air-gapped (or offline) environments
connected to the internet, in what is sometimes known as an offline,
limited connectivity, Local Area Network (LAN), Intranet, or "air-gap" In this situation, the GitLab instance can be one or more servers and services that can communicate
environment. on a local network, but with no or very restricted access to the internet. Assume anything within
the GitLab instance and supporting infrastructure (for example, a private Maven repository) can be
accessed through a local network connection. Assume any files from the internet must come in through
physical media (USB drive, hard drive, writeable DVD, etc.).
In this situation, the GitLab instance can be one, or more, servers and services running in a network that can talk to one another, but have zero, or perhaps very restricted access to the internet. Assume anything within the GitLab instance and supporting infrastructure (private Maven repository for example) can be accessed via local network connection. Assume any files from the internet must come in via physical media (USB drive, hard drive). ## Overview
GitLab scanners generally will connect to the internet to download the GitLab scanners generally will connect to the internet to download the
latest sets of signatures, rules, and patches. A few extra steps are necessary latest sets of signatures, rules, and patches. A few extra steps are necessary
to configure the tools to not do this and to still function properly. to configure the tools to function properly by using resources available on your local network.
### Container registries and package repositories ### Container registries and package repositories
At a high-level, each of the security analyzers are delivered as Docker At a high-level, the security analyzers are delivered as Docker images and
containers and reference various package repositories. When you run a job on may leverage various package repositories. When you run a job on
an internet-connected GitLab installation, GitLab checks the GitLab.com-hosted an internet-connected GitLab installation, GitLab checks the GitLab.com-hosted
container registry and package repositories to ensure that you have container registry to check that you have the latest versions of these Docker images
the latest versions. and possibly connect to package repositories to install necessary dependencies.
In an air-gapped environment, this must be disabled so that GitLab.com is not In an air-gapped environment, these checks must be disabled so that GitLab.com is not
queried. Because the GitLab.com registry and repositories are not available, queried. Because the GitLab.com registry and repositories are not available,
you must update each of the scanners to either reference a different, you must update each of the scanners to either reference a different,
internally-hosted registry or provide access to the individual scanner images. internally-hosted registry or provide access to the individual scanner images.
You must also ensure that your app has access to common package repos You must also ensure that your app has access to common package repositories
that are not hosted on GitLab.com, such as npm, yarn, or rubygems. Packages that are not hosted on GitLab.com, such as npm, yarn, or rubygems. Packages
from these repos can be obtained by temporarily connecting to a network or by from these repos can be obtained by temporarily connecting to a network or by
mirroring the packages inside your own offline network. mirroring the packages inside your own offline network.
### Interacting with the vulnerabilities
Once a vulnerability is found, you can interact with it. Read more on how to [interact with the vulnerabilities](../index.md#interacting-with-the-vulnerabilities).
Please note that in some cases the reported vulnerabilities provide metadata that can contain external links exposed in the UI. These links might not be accessible within an air-gapped (or offline) environment.
### Scanner signature and rule updates ### Scanner signature and rule updates
When connected to the internet, some scanners will reference public databases When connected to the internet, some scanners will reference public databases
for the latest sets of signatures and rules to check against. Without connectivity, for the latest sets of signatures and rules to check against. Without connectivity,
this is not possible. Depending on the scanner, you must therefore disable this is not possible. Depending on the scanner, you must therefore disable
these automatic update checks and either use the databases that they came these automatic update checks and either use the databases that they came
with or manually update those databases. with and manually update those databases or provide access to your own copies
hosted within your network.
## Specific scanner instructions ## Specific scanner instructions
......
...@@ -18,9 +18,9 @@ that is provided by [Auto DevOps](../../../topics/autodevops/index.md). ...@@ -18,9 +18,9 @@ that is provided by [Auto DevOps](../../../topics/autodevops/index.md).
GitLab checks the License Compliance report, compares the licenses between the GitLab checks the License Compliance report, compares the licenses between the
source and target branches, and shows the information right on the merge request. source and target branches, and shows the information right on the merge request.
Blacklisted licenses will be clearly visible with an `x` red icon next to them Denied licenses will be clearly visible with an `x` red icon next to them
as well as new licenses which need a decision from you. In addition, you can as well as new licenses which need a decision from you. In addition, you can
[manually approve or blacklist](#project-policies-for-license-compliance) [manually allow or deny](#project-policies-for-license-compliance)
licenses in your project's settings. licenses in your project's settings.
NOTE: **Note:** NOTE: **Note:**
...@@ -33,7 +33,7 @@ compliance report will be shown properly. ...@@ -33,7 +33,7 @@ compliance report will be shown properly.
![License Compliance Widget](img/license_compliance.png) ![License Compliance Widget](img/license_compliance.png)
If you are a project or group Maintainer, you can click on a license to be given If you are a project or group Maintainer, you can click on a license to be given
the choice to approve it or blacklist it. the choice to allow it or deny it.
![License approval decision](img/license_compliance_decision.png) ![License approval decision](img/license_compliance_decision.png)
...@@ -282,9 +282,9 @@ license_scanning: ...@@ -282,9 +282,9 @@ license_scanning:
From the project's settings: From the project's settings:
- The list of licenses and their status can be managed. - The list of licenses and their status can be managed.
- Licenses can be manually approved or blacklisted. - Licenses can be manually allowed or denied.
To approve or blacklist a license: To allow or deny a license:
1. Either use the **Manage licenses** button in the merge request widget, or 1. Either use the **Manage licenses** button in the merge request widget, or
navigate to the project's **Settings > CI/CD** and expand the navigate to the project's **Settings > CI/CD** and expand the
...@@ -298,12 +298,12 @@ To approve or blacklist a license: ...@@ -298,12 +298,12 @@ To approve or blacklist a license:
at the top of the list. at the top of the list.
- Enter arbitrary text in the field at the top of the list. This will cause the text to be - Enter arbitrary text in the field at the top of the list. This will cause the text to be
added as a license name to the list. added as a license name to the list.
1. Select the **Approve** or **Blacklist** radio button to approve or blacklist respectively 1. Select the **Allow** or **Deny** radio button to allow or deny respectively
the selected license. the selected license.
To modify an existing license: To modify an existing license:
1. In the **License Compliance** list, click the **Approved/Declined** dropdown to change it to the desired status. 1. In the **License Compliance** list, click the **Allow/Deny** dropdown to change it to the desired status.
![License Compliance Settings](img/license_compliance_settings_v12_3.png) ![License Compliance Settings](img/license_compliance_settings_v12_3.png)
......
...@@ -837,6 +837,11 @@ Prerequisites for embedding from a Grafana instance: ...@@ -837,6 +837,11 @@ Prerequisites for embedding from a Grafana instance:
## Troubleshooting ## Troubleshooting
When troubleshooting issues with a managed Prometheus app, it is often useful to
[view the Prometheus UI](../../../development/prometheus.md#access-the-ui-of-a-prometheus-managed-application-in-kubernetes).
### "No data found" error on Metrics dashboard page
If the "No data found" screen continues to appear, it could be due to: If the "No data found" screen continues to appear, it could be due to:
- No successful deployments have occurred to this environment. - No successful deployments have occurred to this environment.
......
...@@ -6,7 +6,7 @@ module Gitlab ...@@ -6,7 +6,7 @@ module Gitlab
module StageEvents module StageEvents
class ProductionStageEnd < StageEvent class ProductionStageEnd < StageEvent
def self.name def self.name
PlanStageStart.name _("Issue first depoloyed to production")
end end
def self.identifier def self.identifier
......
...@@ -173,7 +173,7 @@ module Gitlab ...@@ -173,7 +173,7 @@ module Gitlab
end end
def details def details
message_parts[2] message_parts[2]&.gsub(/^Signed-off-by.*$/, '')
end end
def line_too_long?(line) def line_too_long?(line)
......
...@@ -36,6 +36,8 @@ excluded_attributes: ...@@ -36,6 +36,8 @@ excluded_attributes:
- :runners_token_encrypted - :runners_token_encrypted
- :saml_discovery_token - :saml_discovery_token
- :visibility_level - :visibility_level
epics:
- :state_id
methods: methods:
labels: labels:
...@@ -50,6 +52,8 @@ methods: ...@@ -50,6 +52,8 @@ methods:
- :action - :action
lists: lists:
- :list_type - :list_type
epics:
- :state
preloads: preloads:
......
...@@ -6127,19 +6127,19 @@ msgstr "" ...@@ -6127,19 +6127,19 @@ msgstr ""
msgid "CycleAnalyticsEvent|Issue last edited" msgid "CycleAnalyticsEvent|Issue last edited"
msgstr "" msgstr ""
msgid "CycleAnalyticsEvent|Merge Request label was added" msgid "CycleAnalyticsEvent|Merge request closed"
msgstr "" msgstr ""
msgid "CycleAnalyticsEvent|Merge Request label was removed" msgid "CycleAnalyticsEvent|Merge request created"
msgstr "" msgstr ""
msgid "CycleAnalyticsEvent|Merge request closed" msgid "CycleAnalyticsEvent|Merge request first deployed to production"
msgstr "" msgstr ""
msgid "CycleAnalyticsEvent|Merge request created" msgid "CycleAnalyticsEvent|Merge request label was added"
msgstr "" msgstr ""
msgid "CycleAnalyticsEvent|Merge request first deployed to production" msgid "CycleAnalyticsEvent|Merge request label was removed"
msgstr "" msgstr ""
msgid "CycleAnalyticsEvent|Merge request last build finish time" msgid "CycleAnalyticsEvent|Merge request last build finish time"
...@@ -11161,6 +11161,9 @@ msgstr "" ...@@ -11161,6 +11161,9 @@ msgstr ""
msgid "Issue events" msgid "Issue events"
msgstr "" msgstr ""
msgid "Issue first depoloyed to production"
msgstr ""
msgid "Issue or Merge Request ID is required" msgid "Issue or Merge Request ID is required"
msgstr "" msgstr ""
...@@ -17972,6 +17975,9 @@ msgstr "" ...@@ -17972,6 +17975,9 @@ msgstr ""
msgid "Serverless|Getting started with serverless" msgid "Serverless|Getting started with serverless"
msgstr "" msgstr ""
msgid "Serverless|Help shape the future of Serverless at GitLab"
msgstr ""
msgid "Serverless|If you believe none of these apply, please check back later as the function data may be in the process of becoming available." msgid "Serverless|If you believe none of these apply, please check back later as the function data may be in the process of becoming available."
msgstr "" msgstr ""
...@@ -17984,6 +17990,9 @@ msgstr "" ...@@ -17984,6 +17990,9 @@ msgstr ""
msgid "Serverless|No functions available" msgid "Serverless|No functions available"
msgstr "" msgstr ""
msgid "Serverless|Sign up for First Look"
msgstr ""
msgid "Serverless|The deploy job has not finished." msgid "Serverless|The deploy job has not finished."
msgstr "" msgstr ""
...@@ -17993,6 +18002,9 @@ msgstr "" ...@@ -17993,6 +18002,9 @@ msgstr ""
msgid "Serverless|There is currently no function data available from Knative. This could be for a variety of reasons including:" msgid "Serverless|There is currently no function data available from Knative. This could be for a variety of reasons including:"
msgstr "" msgstr ""
msgid "Serverless|We are continually striving to improve our Serverless functionality. As a Knative user, we would love to hear how we can make this experience better for you. Sign up for GitLab First Look today and we will be in touch shortly."
msgstr ""
msgid "Serverless|Your %{startTag}.gitlab-ci.yml%{endTag} file is not properly configured." msgid "Serverless|Your %{startTag}.gitlab-ci.yml%{endTag} file is not properly configured."
msgstr "" msgstr ""
......
# frozen_string_literal: true
module RuboCop
module Cop
module Performance
class ReadlinesEach < RuboCop::Cop::Cop
MESSAGE = 'Avoid `IO.readlines.each`, since it reads contents into memory in full. ' \
'Use `IO.each_line` or `IO.each` instead.'
def_node_matcher :full_file_read_via_class?, <<~PATTERN
(send
(send (const nil? {:IO :File}) :readlines _) :each)
PATTERN
def_node_matcher :full_file_read_via_instance?, <<~PATTERN
(... (... :readlines) :each)
PATTERN
def on_send(node)
full_file_read_via_class?(node) { add_offense(node, location: :selector, message: MESSAGE) }
full_file_read_via_instance?(node) { add_offense(node, location: :selector, message: MESSAGE) }
end
def autocorrect(node)
lambda do |corrector|
corrector.replace(node.loc.expression, node.source.gsub('readlines.each', 'each_line'))
end
end
end
end
end
end
...@@ -127,6 +127,10 @@ describe Admin::ApplicationSettingsController do ...@@ -127,6 +127,10 @@ describe Admin::ApplicationSettingsController do
end end
describe 'verify panel actions' do describe 'verify panel actions' do
before do
stub_feature_flags(instance_level_integrations: false)
end
Admin::ApplicationSettingsController::VALID_SETTING_PANELS.each do |valid_action| Admin::ApplicationSettingsController::VALID_SETTING_PANELS.each do |valid_action|
it_behaves_like 'renders correct panels' do it_behaves_like 'renders correct panels' do
let(:action) { valid_action } let(:action) { valid_action }
......
...@@ -24,6 +24,18 @@ describe Admin::ProjectsController do ...@@ -24,6 +24,18 @@ describe Admin::ProjectsController do
expect(response.body).not_to match(project.name) expect(response.body).not_to match(project.name)
end end
it 'retrieves archived and non archived corrupted projects when last_repository_check_failed is true' do
archived_corrupted_project = create(:project, :public, :archived, :last_repository_check_failed, name: 'CorruptedArchived', path: 'A')
corrupted_project = create(:project, :public, :last_repository_check_failed, name: 'CorruptedOnly', path: 'C')
get :index, params: { last_repository_check_failed: true }
expect(response).to have_gitlab_http_status(:ok)
expect(response.body).not_to match(project.name)
expect(response.body).to match(archived_corrupted_project.name)
expect(response.body).to match(corrupted_project.name)
end
it 'does not respond with projects pending deletion' do it 'does not respond with projects pending deletion' do
pending_delete_project = create(:project, pending_delete: true) pending_delete_project = create(:project, pending_delete: true)
......
...@@ -114,6 +114,10 @@ FactoryBot.define do ...@@ -114,6 +114,10 @@ FactoryBot.define do
archived { true } archived { true }
end end
trait :last_repository_check_failed do
last_repository_check_failed { true }
end
storage_version { Project::LATEST_STORAGE_VERSION } storage_version { Project::LATEST_STORAGE_VERSION }
trait :legacy_storage do trait :legacy_storage do
......
...@@ -194,6 +194,13 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc ...@@ -194,6 +194,13 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
expect(page).to have_content "Application settings saved successfully" expect(page).to have_content "Application settings saved successfully"
expect(current_settings.terminal_max_session_time).to eq(15) expect(current_settings.terminal_max_session_time).to eq(15)
end end
end
context 'Integrations page' do
before do
stub_feature_flags(instance_level_integrations: false)
visit integrations_admin_application_settings_path
end
it 'Enable hiding third party offers' do it 'Enable hiding third party offers' do
page.within('.as-third-party-offers') do page.within('.as-third-party-offers') do
......
...@@ -205,10 +205,11 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do ...@@ -205,10 +205,11 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
let(:admin) { create(:admin) } let(:admin) { create(:admin) }
before do before do
stub_feature_flags(instance_level_integrations: false)
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(admin) sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin) gitlab_enable_admin_mode_sign_in(admin)
visit general_admin_application_settings_path visit integrations_admin_application_settings_path
end end
it 'user does not see the offer' do it 'user does not see the offer' do
......
...@@ -1492,7 +1492,7 @@ ...@@ -1492,7 +1492,7 @@
"closed_at": null, "closed_at": null,
"parent_id": null, "parent_id": null,
"relative_position": null, "relative_position": null,
"state_id": "opened", "state": "opened",
"start_date_sourcing_epic_id": null, "start_date_sourcing_epic_id": null,
"due_date_sourcing_epic_id": null, "due_date_sourcing_epic_id": null,
"notes": [] "notes": []
...@@ -1524,7 +1524,7 @@ ...@@ -1524,7 +1524,7 @@
"closed_at": null, "closed_at": null,
"parent_id": null, "parent_id": null,
"relative_position": null, "relative_position": null,
"state_id": "opened", "state": "closed",
"start_date_sourcing_epic_id": null, "start_date_sourcing_epic_id": null,
"due_date_sourcing_epic_id": null, "due_date_sourcing_epic_id": null,
"notes": [] "notes": []
...@@ -1556,7 +1556,7 @@ ...@@ -1556,7 +1556,7 @@
"closed_at": null, "closed_at": null,
"parent_id": null, "parent_id": null,
"relative_position": null, "relative_position": null,
"state_id": "opened", "state": "opened",
"start_date_sourcing_epic_id": null, "start_date_sourcing_epic_id": null,
"due_date_sourcing_epic_id": null, "due_date_sourcing_epic_id": null,
"notes": [] "notes": []
...@@ -1588,7 +1588,7 @@ ...@@ -1588,7 +1588,7 @@
"closed_at": null, "closed_at": null,
"parent_id": null, "parent_id": null,
"relative_position": null, "relative_position": null,
"state_id": "opened", "state": "closed",
"start_date_sourcing_epic_id": null, "start_date_sourcing_epic_id": null,
"due_date_sourcing_epic_id": null, "due_date_sourcing_epic_id": null,
"notes": [] "notes": []
...@@ -1620,7 +1620,7 @@ ...@@ -1620,7 +1620,7 @@
"closed_at": null, "closed_at": null,
"parent_id": null, "parent_id": null,
"relative_position": null, "relative_position": null,
"state_id": "opened", "state": "opened",
"start_date_sourcing_epic_id": null, "start_date_sourcing_epic_id": null,
"due_date_sourcing_epic_id": null, "due_date_sourcing_epic_id": null,
"notes": [] "notes": []
......
import { shallowMount } from '@vue/test-utils';
import Cookies from 'js-cookie';
import SurveyBanner from '~/serverless/survey_banner.vue';
import { GlBanner } from '@gitlab/ui';
describe('Knative survey banner', () => {
let wrapper;
function mountBanner() {
wrapper = shallowMount(SurveyBanner, {
propsData: {
surveyUrl: 'http://somesurvey.com/',
},
});
}
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('should render the banner when the cookie is absent', () => {
jest.spyOn(Cookies, 'get').mockReturnValue(undefined);
mountBanner();
expect(Cookies.get).toHaveBeenCalled();
expect(wrapper.find(GlBanner).exists()).toBe(true);
});
it('should close the banner and set a cookie when close button is clicked', () => {
jest.spyOn(Cookies, 'get').mockReturnValue(undefined);
jest.spyOn(Cookies, 'set');
mountBanner();
expect(wrapper.find(GlBanner).exists()).toBe(true);
wrapper.find(GlBanner).vm.$emit('close');
return wrapper.vm.$nextTick().then(() => {
expect(Cookies.set).toHaveBeenCalledWith('hide_serverless_survey', 'true', { expires: 3650 });
expect(wrapper.find(GlBanner).exists()).toBe(false);
});
});
it('should not render the banner when the cookie is set', () => {
jest.spyOn(Cookies, 'get').mockReturnValue('true');
mountBanner();
expect(Cookies.get).toHaveBeenCalled();
expect(wrapper.find(GlBanner).exists()).toBe(false);
});
});
...@@ -7,7 +7,7 @@ describe GitlabSchema.types['Environment'] do ...@@ -7,7 +7,7 @@ describe GitlabSchema.types['Environment'] do
it 'has the expected fields' do it 'has the expected fields' do
expected_fields = %w[ expected_fields = %w[
name id name id state
] ]
expect(described_class).to have_graphql_fields(*expected_fields) expect(described_class).to have_graphql_fields(*expected_fields)
......
...@@ -86,6 +86,7 @@ describe Gitlab::Danger::CommitLinter do ...@@ -86,6 +86,7 @@ describe Gitlab::Danger::CommitLinter do
"A commit message" | false "A commit message" | false
"A commit message\n" | false "A commit message\n" | false
"A commit message\n\n" | false "A commit message\n\n" | false
"A commit message\n\nSigned-off-by: User Name <user@name.me>" | false
"A commit message\n\nWith details" | true "A commit message\n\nWith details" | true
end end
......
...@@ -7,7 +7,7 @@ describe BulkInsertSafe do ...@@ -7,7 +7,7 @@ describe BulkInsertSafe do
include BulkInsertSafe include BulkInsertSafe
include ShaAttribute include ShaAttribute
validates :name, :enum_value, :secret_value, :sha_value, presence: true validates :name, :enum_value, :secret_value, :sha_value, :jsonb_value, presence: true
ENUM_VALUES = { ENUM_VALUES = {
case_1: 1 case_1: 1
...@@ -26,6 +26,7 @@ describe BulkInsertSafe do ...@@ -26,6 +26,7 @@ describe BulkInsertSafe do
default_value_for :enum_value, 'case_1' default_value_for :enum_value, 'case_1'
default_value_for :secret_value, 'my-secret' default_value_for :secret_value, 'my-secret'
default_value_for :sha_value, '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12' default_value_for :sha_value, '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12'
default_value_for :jsonb_value, { "key" => "value" }
def self.valid_list(count) def self.valid_list(count)
Array.new(count) { |n| new(name: "item-#{n}") } Array.new(count) { |n| new(name: "item-#{n}") }
...@@ -60,6 +61,7 @@ describe BulkInsertSafe do ...@@ -60,6 +61,7 @@ describe BulkInsertSafe do
t.text :encrypted_secret_value, null: false t.text :encrypted_secret_value, null: false
t.string :encrypted_secret_value_iv, null: false t.string :encrypted_secret_value_iv, null: false
t.binary :sha_value, null: false, limit: 20 t.binary :sha_value, null: false, limit: 20
t.jsonb :jsonb_value, null: false
t.index :name, unique: true t.index :name, unique: true
end end
...@@ -114,7 +116,7 @@ describe BulkInsertSafe do ...@@ -114,7 +116,7 @@ describe BulkInsertSafe do
described_class.bulk_insert!(items) described_class.bulk_insert!(items)
attribute_names = described_class.attribute_names - %w[id] attribute_names = described_class.attribute_names - %w[id created_at updated_at]
expect(described_class.last(items.size).pluck(*attribute_names)).to eq( expect(described_class.last(items.size).pluck(*attribute_names)).to eq(
items.pluck(*attribute_names)) items.pluck(*attribute_names))
end end
......
...@@ -64,7 +64,7 @@ describe IrkerService do ...@@ -64,7 +64,7 @@ describe IrkerService do
irker.execute(sample_data) irker.execute(sample_data)
conn = @irker_server.accept conn = @irker_server.accept
conn.readlines.each do |line| conn.each_line do |line|
msg = JSON.parse(line.chomp("\n")) msg = JSON.parse(line.chomp("\n"))
expect(msg.keys).to match_array(%w(to privmsg)) expect(msg.keys).to match_array(%w(to privmsg))
expect(msg['to']).to match_array(["irc://chat.freenode.net/#commits", expect(msg['to']).to match_array(["irc://chat.freenode.net/#commits",
......
...@@ -149,6 +149,47 @@ describe Service do ...@@ -149,6 +149,47 @@ describe Service do
end end
end end
describe '.find_or_initialize_instances' do
shared_examples 'service instances' do
it 'returns the available service instances' do
expect(Service.find_or_initialize_instances.pluck(:type)).to match_array(Service.available_services_types)
end
it 'does not create service instances' do
expect { Service.find_or_initialize_instances }.not_to change { Service.count }
end
end
it_behaves_like 'service instances'
context 'with all existing instances' do
before do
Service.insert_all(
Service.available_services_types.map { |type| { instance: true, type: type } }
)
end
it_behaves_like 'service instances'
context 'with a previous existing service (Previous) and a new service (Asana)' do
before do
Service.insert(type: 'PreviousService', instance: true)
Service.delete_by(type: 'AsanaService', instance: true)
end
it_behaves_like 'service instances'
end
end
context 'with a few existing instances' do
before do
create(:jira_service, :instance)
end
it_behaves_like 'service instances'
end
end
describe 'template' do describe 'template' do
let(:project) { create(:project) } let(:project) { create(:project) }
...@@ -173,7 +214,7 @@ describe Service do ...@@ -173,7 +214,7 @@ describe Service do
end end
it 'does not create service templates' do it 'does not create service templates' do
expect { Service.find_or_create_templates }.to change { Service.count }.by(0) expect { Service.find_or_create_templates }.not_to change { Service.count }
end end
it_behaves_like 'retrieves service templates' it_behaves_like 'retrieves service templates'
......
# frozen_string_literal: true
require 'fast_spec_helper'
require_relative '../../../support/helpers/expect_offense'
require_relative '../../../../rubocop/cop/performance/readlines_each'
describe RuboCop::Cop::Performance::ReadlinesEach do
include CopHelper
include ExpectOffense
subject(:cop) { described_class.new }
let(:message) { 'Avoid `IO.readlines.each`, since it reads contents into memory in full. Use `IO.each_line` or `IO.each` instead.' }
shared_examples_for(:class_read) do |klass|
context "and it is called as a class method on #{klass}" do
# We can't use `expect_offense` here because indentation changes based on `klass`
it 'flags it as an offense' do
inspect_source "#{klass}.readlines(file_path).each { |line| puts line }"
expect(cop.offenses.map(&:cop_name)).to contain_exactly('Performance/ReadlinesEach')
end
end
context 'when just using readlines without each' do
it 'does not flag it as an offense' do
expect_no_offenses "contents = #{klass}.readlines(file_path)"
end
end
end
context 'when reading all lines using IO.readlines.each' do
%w(IO File).each do |klass|
it_behaves_like(:class_read, klass)
end
context 'and it is called as an instance method on a return value' do
it 'flags it as an offense' do
expect_offense <<~SOURCE
get_file.readlines.each { |line| puts line }
^^^^ #{message}
SOURCE
end
end
context 'and it is called as an instance method on an assigned variable' do
it 'flags it as an offense' do
expect_offense <<~SOURCE
file = File.new(path)
file.readlines.each { |line| puts line }
^^^^ #{message}
SOURCE
end
end
context 'and it is called as an instance method on a new object' do
it 'flags it as an offense' do
expect_offense <<~SOURCE
File.new(path).readlines.each { |line| puts line }
^^^^ #{message}
SOURCE
end
end
it 'autocorrects `readlines.each` to `each_line`' do
expect(autocorrect_source('obj.readlines.each { |line| line }')).to(
eq('obj.each_line { |line| line }')
)
end
end
context 'when just using readlines without each' do
it 'does not flag it as an offense' do
expect_no_offenses 'contents = my_file.readlines'
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