summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml9
-rw-r--r--.prettierrc10
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/emoji/index.js10
-rw-r--r--app/assets/javascripts/environments/components/container.vue20
-rw-r--r--app/assets/javascripts/environments/components/environment_item.vue12
-rw-r--r--app/assets/javascripts/environments/mixins/container_mixin.js29
-rw-r--r--app/assets/javascripts/environments/mixins/environment_item_mixin.js13
-rw-r--r--changelogs/unreleased/10029-env-item.yml5
-rw-r--r--config/initializers/rspec_profiling.rb50
-rw-r--r--config/karma.config.js10
-rw-r--r--config/webpack.config.js6
-rw-r--r--db/fixtures/development/02_settings.rb (renamed from db/fixtures/development/03_settings.rb)0
-rw-r--r--db/fixtures/development/03_project.rb (renamed from db/fixtures/development/04_project.rb)2
-rw-r--r--db/fixtures/development/04_labels.rb49
-rw-r--r--db/fixtures/development/09_issues.rb6
-rw-r--r--db/fixtures/development/10_merge_requests.rb6
-rw-r--r--db/fixtures/development/22_labeled_issues_seed.rb103
-rw-r--r--doc/ci/triggers/README.md9
-rw-r--r--doc/ci/yaml/README.md15
-rw-r--r--doc/development/testing_guide/frontend_testing.md30
-rw-r--r--doc/user/instance_statistics/convdev.md2
-rw-r--r--lib/gitlab/danger/teammate.rb8
-rw-r--r--lib/gitlab/gitaly_client.rb16
-rw-r--r--locale/gitlab.pot3
-rw-r--r--package.json2
-rw-r--r--scripts/frontend/postinstall.js2
-rw-r--r--scripts/frontend/prettier.js4
-rwxr-xr-xscripts/insert-rspec-profiling-data47
-rw-r--r--spec/javascripts/fixtures/emojis.rb2
-rw-r--r--spec/lib/gitlab/danger/teammate_spec.rb39
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb38
-rw-r--r--yarn.lock10
33 files changed, 375 insertions, 194 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index bd29a266ccd..144063f208f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -66,6 +66,7 @@ stages:
paths:
- knapsack/
- rspec_flaky/
+ - rspec_profiling/
.use-pg: &use-pg
services:
@@ -159,6 +160,7 @@ stages:
- coverage/
- knapsack/
- rspec_flaky/
+ - rspec_profiling/
- tmp/capybara/
reports:
junit: junit_rspec.xml
@@ -336,6 +338,7 @@ retrieve-tests-metadata:
- wget -O $KNAPSACK_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$KNAPSACK_RSPEC_SUITE_REPORT_PATH || rm $KNAPSACK_RSPEC_SUITE_REPORT_PATH
- '[[ -f $KNAPSACK_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${KNAPSACK_RSPEC_SUITE_REPORT_PATH}'
- mkdir -p rspec_flaky/
+ - mkdir -p rspec_profiling/
- wget -O $FLAKY_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$FLAKY_RSPEC_SUITE_REPORT_PATH || rm $FLAKY_RSPEC_SUITE_REPORT_PATH
- '[[ -f $FLAKY_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${FLAKY_RSPEC_SUITE_REPORT_PATH}'
@@ -350,7 +353,7 @@ update-tests-metadata:
- rspec_flaky/
policy: push
script:
- - retry gem install fog-aws mime-types activesupport --no-document
+ - retry gem install fog-aws mime-types activesupport rspec_profiling postgres-copy --no-document
- scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec-pg_node_*.json
- scripts/merge-reports ${FLAKY_RSPEC_SUITE_REPORT_PATH} rspec_flaky/all_*_*.json
- FLAKY_RSPEC_GENERATE_REPORT=1 scripts/prune-old-flaky-specs ${FLAKY_RSPEC_SUITE_REPORT_PATH}
@@ -358,6 +361,7 @@ update-tests-metadata:
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $FLAKY_RSPEC_SUITE_REPORT_PATH'
- rm -f knapsack/${CI_PROJECT_NAME}/*_node_*.json
- rm -f rspec_flaky/all_*.json rspec_flaky/new_*.json
+ - scripts/insert-rspec-profiling-data
flaky-examples-check:
<<: *dedicated-runner
@@ -484,6 +488,9 @@ setup-test-env:
build-qa-image:
<<: *review-docker
+ variables:
+ <<: *review-docker-variables
+ GIT_DEPTH: "20"
stage: prepare
script:
- time docker build --cache-from ${LATEST_QA_IMAGE} --tag ${QA_IMAGE} ./qa/
diff --git a/.prettierrc b/.prettierrc
index 3384551aea5..5e2863a11f6 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,13 +1,5 @@
{
"printWidth": 100,
"singleQuote": true,
- "trailingComma": "es5",
- "overrides": [
- {
- "files": ["**/app/**/*", "**/spec/**/*"],
- "options": {
- "trailingComma": "all"
- }
- }
- ]
+ "trailingComma": "all"
}
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 5ff8c4f5d2a..5db08bf2dc5 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-1.26.0
+1.27.0
diff --git a/app/assets/javascripts/emoji/index.js b/app/assets/javascripts/emoji/index.js
index 36542315c4c..bb5085a1911 100644
--- a/app/assets/javascripts/emoji/index.js
+++ b/app/assets/javascripts/emoji/index.js
@@ -3,6 +3,7 @@ import createFlash from '~/flash';
import { s__ } from '~/locale';
import emojiAliases from 'emojis/aliases.json';
import axios from '../lib/utils/axios_utils';
+import csrf from '../lib/utils/csrf';
import AccessorUtilities from '../lib/utils/accessor';
@@ -24,7 +25,14 @@ export function initEmojiMap() {
resolve(emojiMap);
} else {
// We load the JSON from server
- axios
+ const axiosInstance = axios.create();
+
+ // If the static JSON file is on a CDN we don't want to send the default CSRF token
+ if (gon.asset_host) {
+ delete axiosInstance.defaults.headers.common[csrf.headerKey];
+ }
+
+ axiosInstance
.get(
`${gon.asset_host || ''}${gon.relative_url_root ||
''}/-/emojis/${EMOJI_VERSION}/emojis.json`,
diff --git a/app/assets/javascripts/environments/components/container.vue b/app/assets/javascripts/environments/components/container.vue
index 6ece8b92a30..be80661223c 100644
--- a/app/assets/javascripts/environments/components/container.vue
+++ b/app/assets/javascripts/environments/components/container.vue
@@ -1,14 +1,16 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
-import tablePagination from '../../vue_shared/components/table_pagination.vue';
-import environmentTable from '../components/environments_table.vue';
+import TablePagination from '~/vue_shared/components/table_pagination.vue';
+import containerMixin from 'ee_else_ce/environments/mixins/container_mixin';
+import EnvironmentTable from '../components/environments_table.vue';
export default {
components: {
- environmentTable,
- tablePagination,
+ EnvironmentTable,
+ TablePagination,
GlLoadingIcon,
},
+ mixins: [containerMixin],
props: {
isLoading: {
type: Boolean,
@@ -47,7 +49,15 @@ export default {
<slot name="emptyState"></slot>
<div v-if="!isLoading && environments.length > 0" class="table-holder">
- <environment-table :environments="environments" :can-read-environment="canReadEnvironment" />
+ <environment-table
+ :environments="environments"
+ :can-read-environment="canReadEnvironment"
+ :canary-deployment-feature-id="canaryDeploymentFeatureId"
+ :show-canary-deployment-callout="showCanaryDeploymentCallout"
+ :user-callouts-path="userCalloutsPath"
+ :lock-promotion-svg-path="lockPromotionSvgPath"
+ :help-canary-deployments-path="helpCanaryDeploymentsPath"
+ />
<table-pagination
v-if="pagination && pagination.totalPages > 1"
diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue
index 1e89dce69cb..a092bdfbc6c 100644
--- a/app/assets/javascripts/environments/components/environment_item.vue
+++ b/app/assets/javascripts/environments/components/environment_item.vue
@@ -4,6 +4,7 @@ import _ from 'underscore';
import { GlTooltipDirective } from '@gitlab/ui';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import Icon from '~/vue_shared/components/icon.vue';
+import environmentItemMixin from 'ee_else_ce/environments/mixins/environment_item_mixin';
import ActionsComponent from './environment_actions.vue';
import ExternalUrlComponent from './environment_external_url.vue';
import StopComponent from './environment_stop.vue';
@@ -34,10 +35,10 @@ export default {
TerminalButtonComponent,
MonitoringButtonComponent,
},
-
directives: {
GlTooltip: GlTooltipDirective,
},
+ mixins: [environmentItemMixin],
props: {
model: {
@@ -467,9 +468,18 @@ export default {
<div v-if="!model.isFolder" class="table-mobile-header" role="rowheader">
{{ s__('Environments|Environment') }}
</div>
+
+ <span v-if="shouldRenderDeployBoard" class="deploy-board-icon" @click="toggleDeployBoard">
+ <icon :name="deployIconName" />
+ </span>
+
<span v-if="!model.isFolder" class="environment-name table-mobile-content">
<a class="qa-environment-link" :href="environmentPath"> {{ model.name }} </a>
+ <span v-if="isProtected" class="badge badge-success">
+ {{ s__('Environments|protected') }}
+ </span>
</span>
+
<span v-else class="folder-name" role="button" @click="onClickFolder">
<icon :name="folderIconName" class="folder-icon" />
diff --git a/app/assets/javascripts/environments/mixins/container_mixin.js b/app/assets/javascripts/environments/mixins/container_mixin.js
new file mode 100644
index 00000000000..f2907c120f8
--- /dev/null
+++ b/app/assets/javascripts/environments/mixins/container_mixin.js
@@ -0,0 +1,29 @@
+export default {
+ props: {
+ canaryDeploymentFeatureId: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ showCanaryDeploymentCallout: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ userCalloutsPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ lockPromotionSvgPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ helpCanaryDeploymentsPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+};
diff --git a/app/assets/javascripts/environments/mixins/environment_item_mixin.js b/app/assets/javascripts/environments/mixins/environment_item_mixin.js
new file mode 100644
index 00000000000..2dfed36ec99
--- /dev/null
+++ b/app/assets/javascripts/environments/mixins/environment_item_mixin.js
@@ -0,0 +1,13 @@
+export default {
+ computed: {
+ deployIconName() {
+ return '';
+ },
+ shouldRenderDeployBoard() {
+ return false;
+ },
+ },
+ methods: {
+ toggleDeployBoard() {},
+ },
+};
diff --git a/changelogs/unreleased/10029-env-item.yml b/changelogs/unreleased/10029-env-item.yml
new file mode 100644
index 00000000000..f4e742d3e17
--- /dev/null
+++ b/changelogs/unreleased/10029-env-item.yml
@@ -0,0 +1,5 @@
+---
+title: Removes EE differences for environment_item.vue
+merge_request:
+author:
+type: other
diff --git a/config/initializers/rspec_profiling.rb b/config/initializers/rspec_profiling.rb
index 2de310753a9..715e17057e0 100644
--- a/config/initializers/rspec_profiling.rb
+++ b/config/initializers/rspec_profiling.rb
@@ -1,7 +1,28 @@
+# frozen_string_literal: true
+
+return unless Rails.env.test?
+
module RspecProfilingExt
- module PSQL
- def establish_connection
- ::RspecProfiling::Collectors::PSQL::Result.establish_connection(ENV['RSPEC_PROFILING_POSTGRES_URL'])
+ module Collectors
+ class CSVWithTimestamps < ::RspecProfiling::Collectors::CSV
+ TIMESTAMP_FIELDS = %w(created_at updated_at).freeze
+ HEADERS = (::RspecProfiling::Collectors::CSV::HEADERS + TIMESTAMP_FIELDS).freeze
+
+ def insert(attributes)
+ output << HEADERS.map do |field|
+ if TIMESTAMP_FIELDS.include?(field)
+ Time.now
+ else
+ attributes.fetch(field.to_sym)
+ end
+ end
+ end
+
+ private
+
+ def output
+ @output ||= ::CSV.open(path, "w").tap { |csv| csv << HEADERS }
+ end
end
end
@@ -10,9 +31,13 @@ module RspecProfilingExt
if ENV['CI_COMMIT_REF_NAME']
"#{defined?(Gitlab::License) ? 'ee' : 'ce'}:#{ENV['CI_COMMIT_REF_NAME']}"
else
- super
+ super&.chomp
end
end
+
+ def sha
+ super&.chomp
+ end
end
module Run
@@ -30,16 +55,11 @@ module RspecProfilingExt
end
end
-if Rails.env.test?
- RspecProfiling.configure do |config|
- if ENV['RSPEC_PROFILING_POSTGRES_URL'].present?
- RspecProfiling::Collectors::PSQL.prepend(RspecProfilingExt::PSQL)
- config.collector = RspecProfiling::Collectors::PSQL
- end
-
- if ENV.key?('CI')
- RspecProfiling::VCS::Git.prepend(RspecProfilingExt::Git)
- RspecProfiling::Run.prepend(RspecProfilingExt::Run)
- end
+RspecProfiling.configure do |config|
+ if ENV.key?('CI') || ENV.key?('RSPEC_PROFILING')
+ RspecProfiling::VCS::Git.prepend(RspecProfilingExt::Git)
+ RspecProfiling::Run.prepend(RspecProfilingExt::Run)
+ config.collector = RspecProfilingExt::Collectors::CSVWithTimestamps
+ config.csv_path = -> { "rspec_profiling/#{Time.now.to_i}-#{SecureRandom.hex(8)}-rspec-data.csv" }
end
end
diff --git a/config/karma.config.js b/config/karma.config.js
index 1012a713eb6..23eae40dceb 100644
--- a/config/karma.config.js
+++ b/config/karma.config.js
@@ -26,7 +26,7 @@ webpackConfig.devtool = 'cheap-inline-source-map';
webpackConfig.plugins.push(
new webpack.DefinePlugin({
'process.env.BABEL_ENV': JSON.stringify(process.env.BABEL_ENV || process.env.NODE_ENV || null),
- })
+ }),
);
const specFilters = argumentsParser
@@ -37,7 +37,7 @@ const specFilters = argumentsParser
memo.push(filter, filter.replace(/\/?$/, '/**/*.js'));
return memo;
},
- []
+ [],
)
.parse(process.argv).filterSpec;
@@ -51,7 +51,7 @@ if (specFilters.length) {
root: ROOT_PATH,
matchBase: true,
})
- .filter(path => path.endsWith('spec.js'))
+ .filter(path => path.endsWith('spec.js')),
);
// flatten
@@ -78,8 +78,8 @@ if (specFilters.length) {
new webpack.ContextReplacementPlugin(
/spec[\\\/]javascripts$/,
path.join(ROOT_PATH, 'spec/javascripts'),
- newContext
- )
+ newContext,
+ ),
);
}
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 64e6ec49219..11970b620bc 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -251,7 +251,7 @@ module.exports = {
} else {
resource.request = path.join(
ROOT_PATH,
- 'app/assets/javascripts/vue_shared/components/empty_component.js'
+ 'app/assets/javascripts/vue_shared/components/empty_component.js',
);
}
}),
@@ -267,7 +267,7 @@ module.exports = {
const missingDeps = Array.from(compilation.missingDependencies);
const nodeModulesPath = path.join(ROOT_PATH, 'node_modules');
const hasMissingNodeModules = missingDeps.some(
- file => file.indexOf(nodeModulesPath) !== -1
+ file => file.indexOf(nodeModulesPath) !== -1,
);
// watch for changes to missing node_modules
@@ -278,7 +278,7 @@ module.exports = {
// report our auto-generated bundle count
console.log(
- `${autoEntriesCount} entries from '/pages' automatically added to webpack output.`
+ `${autoEntriesCount} entries from '/pages' automatically added to webpack output.`,
);
callback();
diff --git a/db/fixtures/development/03_settings.rb b/db/fixtures/development/02_settings.rb
index 3a4a5d436bf..3a4a5d436bf 100644
--- a/db/fixtures/development/03_settings.rb
+++ b/db/fixtures/development/02_settings.rb
diff --git a/db/fixtures/development/04_project.rb b/db/fixtures/development/03_project.rb
index 9a5f7cf8175..46018cf68aa 100644
--- a/db/fixtures/development/04_project.rb
+++ b/db/fixtures/development/03_project.rb
@@ -60,7 +60,7 @@ Sidekiq::Testing.inline! do
path: group_path
)
group.description = FFaker::Lorem.sentence
- group.save
+ group.save!
group.add_owner(User.first)
end
diff --git a/db/fixtures/development/04_labels.rb b/db/fixtures/development/04_labels.rb
new file mode 100644
index 00000000000..b9ae4098d76
--- /dev/null
+++ b/db/fixtures/development/04_labels.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'digest/md5'
+
+class Gitlab::Seeder::GroupLabels
+ def initialize(group, label_per_group: 10)
+ @group = group
+ @label_per_group = label_per_group
+ end
+
+ def seed!
+ @label_per_group.times do
+ label_title = FFaker::Product.brand
+ Labels::CreateService
+ .new(title: label_title, color: "##{Digest::MD5.hexdigest(label_title)[0..5]}")
+ .execute(group: @group)
+ print '.'
+ end
+ end
+end
+
+class Gitlab::Seeder::ProjectLabels
+ def initialize(project, label_per_project: 5)
+ @project = project
+ @label_per_project = label_per_project
+ end
+
+ def seed!
+ @label_per_project.times do
+ label_title = FFaker::Vehicle.model
+ Labels::CreateService
+ .new(title: label_title, color: "##{Digest::MD5.hexdigest(label_title)[0..5]}")
+ .execute(project: @project)
+ print '.'
+ end
+ end
+end
+
+Gitlab::Seeder.quiet do
+ puts "\nGenerating group labels"
+ Group.all.find_each do |group|
+ Gitlab::Seeder::GroupLabels.new(group).seed!
+ end
+
+ puts "\nGenerating project labels"
+ Project.all.find_each do |project|
+ Gitlab::Seeder::ProjectLabels.new(project).seed!
+ end
+end
diff --git a/db/fixtures/development/09_issues.rb b/db/fixtures/development/09_issues.rb
index 16243b72f9a..926401d8b9e 100644
--- a/db/fixtures/development/09_issues.rb
+++ b/db/fixtures/development/09_issues.rb
@@ -3,13 +3,17 @@ require './spec/support/sidekiq'
Gitlab::Seeder.quiet do
Project.all.each do |project|
10.times do
+ label_ids = project.labels.pluck(:id).sample(3)
+ label_ids += project.group.labels.sample(3) if project.group
+
issue_params = {
title: FFaker::Lorem.sentence(6),
description: FFaker::Lorem.sentence,
state: ['opened', 'closed'].sample,
milestone: project.milestones.sample,
assignees: [project.team.users.sample],
- created_at: rand(12).months.ago
+ created_at: rand(12).months.ago,
+ label_ids: label_ids
}
Issues::CreateService.new(project, project.team.users.sample, issue_params).execute
diff --git a/db/fixtures/development/10_merge_requests.rb b/db/fixtures/development/10_merge_requests.rb
index 2051bcff8f0..1952f84ed62 100644
--- a/db/fixtures/development/10_merge_requests.rb
+++ b/db/fixtures/development/10_merge_requests.rb
@@ -12,13 +12,17 @@ Gitlab::Seeder.quiet do
source_branch = branches.pop
target_branch = branches.pop
+ label_ids = project.labels.pluck(:id).sample(3)
+ label_ids += project.group.labels.sample(3) if project.group
+
params = {
source_branch: source_branch,
target_branch: target_branch,
title: FFaker::Lorem.sentence(6),
description: FFaker::Lorem.sentences(3).join(" "),
milestone: project.milestones.sample,
- assignee: project.team.users.sample
+ assignee: project.team.users.sample,
+ label_ids: label_ids
}
# Only create MRs with users that are allowed to create MRs
diff --git a/db/fixtures/development/22_labeled_issues_seed.rb b/db/fixtures/development/22_labeled_issues_seed.rb
deleted file mode 100644
index 3730e9c7958..00000000000
--- a/db/fixtures/development/22_labeled_issues_seed.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-# Creates a project with labeled issues for an user.
-# Run this single seed file using: rake db:seed_fu FILTER=labeled USER_ID=74.
-# If an USER_ID is not provided it will use the last created user.
-require './spec/support/sidekiq'
-
-class Gitlab::Seeder::LabeledIssues
- include ::Gitlab::Utils
-
- def initialize(user)
- @user = user
- end
-
- def seed!
- Sidekiq::Testing.inline! do
- group = create_group
-
- create_projects(group)
- create_labels(group)
- create_issues(group)
- end
-
- print '.'
- end
-
- private
-
- def create_group
- group_name = "group_of_#{@user.username}_#{SecureRandom.hex(4)}"
-
- group_params = {
- name: group_name,
- path: group_name,
- description: FFaker::Lorem.sentence
- }
-
- Groups::CreateService.new(@user, group_params).execute
- end
-
- def create_projects(group)
- 5.times do
- project_name = "project_#{SecureRandom.hex(6)}"
-
- params = {
- namespace_id: group.id,
- name: project_name,
- description: FFaker::Lorem.sentence,
- visibility_level: Gitlab::VisibilityLevel.values.sample
- }
-
- Projects::CreateService.new(@user, params).execute
- end
- end
-
- def create_labels(group)
- group.projects.each do |project|
- 5.times do
- label_title = FFaker::Vehicle.model
- Labels::CreateService.new(title: label_title, color: "#69D100").execute(project: project)
- end
- end
-
- 10.times do
- label_title = FFaker::Product.brand
- Labels::CreateService.new(title: label_title).execute(group: group)
- end
- end
-
- def create_issues(group)
- # Get only group labels
- group_labels =
- LabelsFinder.new(@user, group_id: group.id).execute.where.not(group_id: nil)
-
- group.projects.each do |project|
- label_ids = project.labels.pluck(:id).sample(5)
- label_ids.push(*group.labels.sample(4))
-
- 20.times do
- issue_params = {
- title: FFaker::Lorem.sentence(6),
- description: FFaker::Lorem.sentence,
- state: 'opened',
- label_ids: label_ids
-
- }
-
- Issues::CreateService.new(project, @user, issue_params).execute if project.project_feature.present?
- end
- end
- end
-end
-
-Gitlab::Seeder.quiet do
- user_id = ENV['USER_ID']
-
- user =
- if user_id.present?
- User.find(user_id)
- else
- User.last
- end
-
- Gitlab::Seeder::LabeledIssues.new(user).seed!
-end
diff --git a/doc/ci/triggers/README.md b/doc/ci/triggers/README.md
index bceccf4d40d..398b017277f 100644
--- a/doc/ci/triggers/README.md
+++ b/doc/ci/triggers/README.md
@@ -17,6 +17,12 @@ The following methods of authentication are supported.
A unique trigger token can be obtained when [adding a new trigger](#adding-a-new-trigger).
+DANGER: **Danger:**
+Passing plain text tokens in public projects is a security issue. Potential
+attackers can impersonate the user that exposed their trigger token publicly in
+their `.gitlab-ci.yml` file. Use [variables](../variables/README.md#variables)
+to protect trigger tokens.
+
## Adding a new trigger
You can add a new trigger by going to your project's
@@ -53,9 +59,6 @@ The action is irreversible.
>
> - Valid refs are only the branches and tags. If you pass a commit SHA as a ref,
> it will not trigger a job.
-> - If your project is public, passing the token in plain text is probably not the
-> wisest idea, so you might want to use a
-> [variable](../variables/README.md#variables) for that purpose.
To trigger a job you need to send a `POST` request to GitLab's API endpoint:
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index f170323059a..a44f4b62a0e 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -367,10 +367,11 @@ job:
- branches@gitlab-org/gitlab-ce
except:
- master@gitlab-org/gitlab-ce
+ - release/.*@gitlab-org/gitlab-ce
```
The above example will run `job` for all branches on `gitlab-org/gitlab-ce`,
-except master.
+except `master` and those with names prefixed with `release/`.
If a job does not have an `only` rule, `only: ['branches', 'tags']` is set by
default. If it doesn't have an `except` rule, it is empty.
@@ -1756,7 +1757,7 @@ include:
```
All [nested includes](#nested-includes) will be executed in the scope of the target project,
-so it is possible to used local (relative to target project), project, remote
+so it is possible to use local (relative to target project), project, remote
or template includes.
#### `include:template`
@@ -1792,9 +1793,17 @@ include:
All nested includes will be executed without context as public user, so only another remote,
or public project, or template is allowed.
+NOTE: **Note:**
+Changes to remote includes will not have effect on already created pipelines,
+because the include is being evaluated at the time of pipeline creation.
+This is when full definition of CI yaml is being expanded in order to create
+pipeline with stages with jobs. You always retry job that is already created,
+thus created after pipeline creation. To re-include all (thus re-evaluate the
+configuration), you have to re-create pipeline.
+
#### Nested includes
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/53903) in GitLab 11.7.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/56836) in GitLab 11.9.
Nested includes allow you to compose a set of includes.
A total of 50 includes is allowed.
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index 5b66e513a76..9bfb1e69f9e 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -35,15 +35,16 @@ If your test exceeds that time, it will fail.
If you cannot improve the performance of the tests, you can increase the timeout
for a specific test using
-[`jest.setTimeout`](https://jestjs.io/docs/en/jest-object#jestsettimeouttimeout).
+[`setTestTimeout`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/spec/frontend/helpers/timeout.js).
```javascript
-beforeAll(() => {
- jest.setTimeout(500);
-});
+import { setTestTimeout } from 'helpers/timeout';
describe('Component', () => {
- // ...
+ it('does something amazing', () => {
+ setTestTimeout(500);
+ // ...
+ });
});
```
@@ -281,25 +282,6 @@ Information on setting up and running RSpec integration tests with
## Gotchas
-### Errors due to use of unsupported JavaScript features
-
-Similar errors will be thrown if you're using JavaScript features not yet
-supported by the PhantomJS test runner which is used for both Karma and RSpec
-tests. We polyfill some JavaScript objects for older browsers, but some
-features are still unavailable:
-
-- Array.from
-- Array.first
-- Async functions
-- Generators
-- Array destructuring
-- For..Of
-- Symbol/Symbol.iterator
-- Spread
-
-Until these are polyfilled appropriately, they should not be used. Please
-update this list with additional unsupported features.
-
### RSpec errors due to JavaScript
By default RSpec unit tests will not run JavaScript in the headless browser
diff --git a/doc/user/instance_statistics/convdev.md b/doc/user/instance_statistics/convdev.md
index 247be1fb392..2c9e0ecbf65 100644
--- a/doc/user/instance_statistics/convdev.md
+++ b/doc/user/instance_statistics/convdev.md
@@ -2,7 +2,7 @@
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/30469) in GitLab 9.3.
-NOTE: **NOTE**
+NOTE: **Note:**
Your GitLab instance's [usage ping](../admin_area/settings/usage_statistics.md#usage-ping-core-only) must be activated in order to use this feature.
The Conversational Development Index (ConvDev Index) gives you an overview of your entire
diff --git a/lib/gitlab/danger/teammate.rb b/lib/gitlab/danger/teammate.rb
index 4b822aa86c5..bfada512727 100644
--- a/lib/gitlab/danger/teammate.rb
+++ b/lib/gitlab/danger/teammate.rb
@@ -21,21 +21,21 @@ module Gitlab
# Traintainers also count as reviewers
def reviewer?(project, category)
- capabilities(project) == "reviewer #{category}" || traintainer?(project, category)
+ capabilities(project).include?("reviewer #{category}") || traintainer?(project, category)
end
def traintainer?(project, category)
- capabilities(project) == "trainee_maintainer #{category}"
+ capabilities(project).include?("trainee_maintainer #{category}")
end
def maintainer?(project, category)
- capabilities(project) == "maintainer #{category}"
+ capabilities(project).include?("maintainer #{category}")
end
private
def capabilities(project)
- projects.fetch(project, '')
+ Array(projects.fetch(project, []))
end
end
end
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 48c113a8b14..0a371889af2 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -257,8 +257,7 @@ module Gitlab
# This is this actual number of times this call was made. Used for information purposes only
actual_call_count = increment_call_count("gitaly_#{call_site}_actual")
- # Do no enforce limits in production
- return if Rails.env.production? || ENV["GITALY_DISABLE_REQUEST_LIMITS"]
+ return unless enforce_gitaly_request_limits?
# Check if this call is nested within a allow_n_plus_1_calls
# block and skip check if it is
@@ -275,6 +274,19 @@ module Gitlab
raise TooManyInvocationsError.new(call_site, actual_call_count, max_call_count, max_stacks)
end
+ def self.enforce_gitaly_request_limits?
+ # We typically don't want to enforce request limits in production
+ # However, we have some production-like test environments, i.e., ones
+ # where `Rails.env.production?` returns `true`. We do want to be able to
+ # check if the limit is being exceeded while testing in those environments
+ # In that case we can use a feature flag to indicate that we do want to
+ # enforce request limits.
+ return true if feature_enabled?('enforce_requests_limits')
+
+ !(Rails.env.production? || ENV["GITALY_DISABLE_REQUEST_LIMITS"])
+ end
+ private_class_method :enforce_gitaly_request_limits?
+
def self.allow_n_plus_1_calls
return yield unless Gitlab::SafeRequestStore.active?
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index df69e86c1ad..4751b7264a5 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -3196,6 +3196,9 @@ msgstr ""
msgid "Environments|You don't have any environments right now"
msgstr ""
+msgid "Environments|protected"
+msgstr ""
+
msgid "Epic"
msgstr ""
diff --git a/package.json b/package.json
index e9abe6a76d7..60b3203741e 100644
--- a/package.json
+++ b/package.json
@@ -169,7 +169,7 @@
"nodemon": "^1.18.9",
"pixelmatch": "^4.0.2",
"postcss": "^7.0.14",
- "prettier": "1.16.1",
+ "prettier": "1.16.4",
"stylelint": "^9.10.1",
"stylelint-config-recommended": "^2.1.0",
"stylelint-scss": "^3.5.3",
diff --git a/scripts/frontend/postinstall.js b/scripts/frontend/postinstall.js
index 682039a41b3..94977e459e3 100644
--- a/scripts/frontend/postinstall.js
+++ b/scripts/frontend/postinstall.js
@@ -13,7 +13,7 @@ if (process.platform === 'darwin') {
ensure that it is supported by the fsevents library.
You can try installing again with \`${chalk.cyan('yarn install --force')}\`
- `)
+ `),
);
process.exit(1);
}
diff --git a/scripts/frontend/prettier.js b/scripts/frontend/prettier.js
index ffb09ea9779..bf0e98da139 100644
--- a/scripts/frontend/prettier.js
+++ b/scripts/frontend/prettier.js
@@ -32,7 +32,7 @@ let globDir = process.argv[3] || '';
if (globDir && globDir.charAt(globDir.length - 1) !== '/') globDir += '/';
console.log(
- `Loading all ${allFiles ? '' : 'staged '}files ${globDir ? `within ${globDir} ` : ''}...`
+ `Loading all ${allFiles ? '' : 'staged '}files ${globDir ? `within ${globDir} ` : ''}...`,
);
const globPatterns = matchExtensions.map(ext => `${globDir}**/*.${ext}`);
@@ -105,7 +105,7 @@ Promise.all(matchedFiles.map(checkFileWithPrettierConfig))
.then(() => {
const failAction = shouldSave ? 'fixed' : 'failed';
console.log(
- `\nSummary:\n ${matchedCount} files processed (${passedCount} passed, ${failedCount} ${failAction}, ${ignoredCount} ignored)\n`
+ `\nSummary:\n ${matchedCount} files processed (${passedCount} passed, ${failedCount} ${failAction}, ${ignoredCount} ignored)\n`,
);
if (didWarn) process.exit(1);
diff --git a/scripts/insert-rspec-profiling-data b/scripts/insert-rspec-profiling-data
new file mode 100755
index 00000000000..10e337b9972
--- /dev/null
+++ b/scripts/insert-rspec-profiling-data
@@ -0,0 +1,47 @@
+#!/usr/bin/env ruby
+
+require 'csv'
+require 'rspec_profiling'
+require 'postgres-copy'
+
+module RspecProfiling
+ module Collectors
+ class PSQL
+ def establish_connection
+ # This disables the automatic creation of the database and
+ # table. In the future, we may want a way to specify the host of
+ # the database to connect so that we can call #install.
+ Result.establish_connection(results_url)
+ end
+
+ def prepared?
+ connection.data_source_exists?(table)
+ end
+
+ def results_url
+ ENV['RSPEC_PROFILING_POSTGRES_URL']
+ end
+
+ class Result < ActiveRecord::Base
+ acts_as_copy_target
+ end
+ end
+ end
+end
+
+def insert_data(path)
+ puts "#{Time.now} Inserting CI stats..."
+
+ collector = RspecProfiling::Collectors::PSQL.new
+ collector.install
+
+ files = Dir[File.join(path, "*.csv")]
+
+ files.each do |filename|
+ puts "#{Time.now} Inserting #{filename}..."
+ result = RspecProfiling::Collectors::PSQL::Result.copy_from(filename)
+ puts "#{Time.now} Inserted #{result.cmd_tuples} lines in #{filename}, DB response: #{result.cmd_status}"
+ end
+end
+
+insert_data('rspec_profiling') if ENV['RSPEC_PROFILING_POSTGRES_URL'].present?
diff --git a/spec/javascripts/fixtures/emojis.rb b/spec/javascripts/fixtures/emojis.rb
index f5fb008c7b3..4dab697e5e2 100644
--- a/spec/javascripts/fixtures/emojis.rb
+++ b/spec/javascripts/fixtures/emojis.rb
@@ -9,6 +9,8 @@ describe 'Emojis (JavaScript fixtures)' do
it 'emojis/emojis.json' do |example|
JavaScriptFixturesHelpers::FIXTURE_PATHS.each do |fixture_path|
+ next unless File.directory?(fixture_path)
+
# Copying the emojis.json from the public folder
fixture_file_name = File.expand_path('emojis/emojis.json', fixture_path)
FileUtils.mkdir_p(File.dirname(fixture_file_name))
diff --git a/spec/lib/gitlab/danger/teammate_spec.rb b/spec/lib/gitlab/danger/teammate_spec.rb
new file mode 100644
index 00000000000..4bc0a4c1398
--- /dev/null
+++ b/spec/lib/gitlab/danger/teammate_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+describe Gitlab::Danger::Teammate do
+ subject { described_class.new({ 'projects' => projects }) }
+ let(:projects) { { project => capabilities } }
+ let(:project) { double }
+
+ describe 'multiple roles project project' do
+ let(:capabilities) { ['reviewer backend', 'maintainer frontend', 'trainee_maintainer database'] }
+
+ it '#reviewer? supports multiple roles per project' do
+ expect(subject.reviewer?(project, 'backend')).to be_truthy
+ end
+
+ it '#traintainer? supports multiple roles per project' do
+ expect(subject.traintainer?(project, 'database')).to be_truthy
+ end
+
+ it '#maintainer? supports multiple roles per project' do
+ expect(subject.maintainer?(project, 'frontend')).to be_truthy
+ end
+ end
+
+ describe 'one role project project' do
+ let(:capabilities) { 'reviewer backend' }
+
+ it '#reviewer? supports one role per project' do
+ expect(subject.reviewer?(project, 'backend')).to be_truthy
+ end
+
+ it '#traintainer? supports one role per project' do
+ expect(subject.traintainer?(project, 'database')).to be_falsey
+ end
+
+ it '#maintainer? supports one role per project' do
+ expect(subject.maintainer?(project, 'frontend')).to be_falsey
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index cf12baf1a93..f1acb1d9bc4 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -149,11 +149,21 @@ describe Gitlab::GitalyClient do
end
end
- context 'when RequestStore is enabled', :request_store do
+ context 'when RequestStore is enabled and the maximum number of calls is not enforced by a feature flag', :request_store do
+ before do
+ stub_feature_flags(gitaly_enforce_requests_limits: false)
+ end
+
it 'allows up the maximum number of allowed calls' do
expect { call_gitaly(Gitlab::GitalyClient::MAXIMUM_GITALY_CALLS) }.not_to raise_error
end
+ it 'allows the maximum number of calls to be exceeded if GITALY_DISABLE_REQUEST_LIMITS is set' do
+ stub_env('GITALY_DISABLE_REQUEST_LIMITS', 'true')
+
+ expect { call_gitaly(Gitlab::GitalyClient::MAXIMUM_GITALY_CALLS + 1) }.not_to raise_error
+ end
+
context 'when the maximum number of calls has been reached' do
before do
call_gitaly(Gitlab::GitalyClient::MAXIMUM_GITALY_CALLS)
@@ -189,6 +199,32 @@ describe Gitlab::GitalyClient do
end
end
+ context 'in production and when RequestStore is enabled', :request_store do
+ before do
+ allow(Rails.env).to receive(:production?).and_return(true)
+ end
+
+ context 'when the maximum number of calls is enforced by a feature flag' do
+ before do
+ stub_feature_flags(gitaly_enforce_requests_limits: true)
+ end
+
+ it 'does not allow the maximum number of calls to be exceeded' do
+ expect { call_gitaly(Gitlab::GitalyClient::MAXIMUM_GITALY_CALLS + 1) }.to raise_error(Gitlab::GitalyClient::TooManyInvocationsError)
+ end
+ end
+
+ context 'when the maximum number of calls is not enforced by a feature flag' do
+ before do
+ stub_feature_flags(gitaly_enforce_requests_limits: false)
+ end
+
+ it 'allows the maximum number of calls to be exceeded' do
+ expect { call_gitaly(Gitlab::GitalyClient::MAXIMUM_GITALY_CALLS + 1) }.not_to raise_error
+ end
+ end
+ end
+
context 'when RequestStore is not active' do
it 'does not raise errors when the maximum number of allowed calls is exceeded' do
expect { call_gitaly(Gitlab::GitalyClient::MAXIMUM_GITALY_CALLS + 2) }.not_to raise_error
diff --git a/yarn.lock b/yarn.lock
index 9908d829b3a..4456810ec43 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8086,16 +8086,16 @@ prepend-http@^2.0.0:
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
-prettier@1.16.1:
- version "1.16.1"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.1.tgz#534c2c9d7853f8845e5e078384e71973bd74089f"
- integrity sha512-XXUITwIkGb3CPJ2hforHah/zTINRyie5006Jd2HKy2qz7snEJXl0KLfsJZW/wst9g6R2rFvqba3VpNYdu1hDcA==
-
prettier@1.16.3:
version "1.16.3"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.3.tgz#8c62168453badef702f34b45b6ee899574a6a65d"
integrity sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw==
+prettier@1.16.4:
+ version "1.16.4"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.4.tgz#73e37e73e018ad2db9c76742e2647e21790c9717"
+ integrity sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==
+
pretty-format@^24.0.0:
version "24.0.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.0.0.tgz#cb6599fd73ac088e37ed682f61291e4678f48591"