diff options
18 files changed, 453 insertions, 178 deletions
diff --git a/app/assets/javascripts/monitoring/components/charts/time_series.vue b/app/assets/javascripts/monitoring/components/charts/time_series.vue index e77bf08be7f..e79755f4fb2 100644 --- a/app/assets/javascripts/monitoring/components/charts/time_series.vue +++ b/app/assets/javascripts/monitoring/components/charts/time_series.vue @@ -311,7 +311,10 @@ export default { <gl-tooltip :target="() => $refs.graphTitle" :disabled="!showTitleTooltip"> {{ graphData.title }} </gl-tooltip> - <div class="prometheus-graph-widgets js-graph-widgets flex-fill"> + <div + class="prometheus-graph-widgets js-graph-widgets flex-fill" + data-qa-selector="prometheus_graph_widgets" + > <slot></slot> </div> </div> diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index 6178d1fab67..0cdda48f1e5 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -363,7 +363,7 @@ export default { </script> <template> - <div class="prometheus-graphs"> + <div class="prometheus-graphs" data-qa-selector="prometheus_graphs"> <div v-if="showHeader" ref="prometheusGraphsHeader" diff --git a/app/assets/javascripts/monitoring/components/panel_type.vue b/app/assets/javascripts/monitoring/components/panel_type.vue index a2849dcfddb..9c50d3190b9 100644 --- a/app/assets/javascripts/monitoring/components/panel_type.vue +++ b/app/assets/javascripts/monitoring/components/panel_type.vue @@ -138,6 +138,7 @@ export default { v-gl-tooltip class="ml-auto mx-3" toggle-class="btn btn-transparent border-0" + data-qa-selector="prometheus_widgets_dropdown" :right="true" :no-caret="true" :title="__('More actions')" @@ -161,7 +162,11 @@ export default { > {{ __('Generate link to chart') }} </gl-dropdown-item> - <gl-dropdown-item v-if="alertWidgetAvailable" v-gl-modal="`alert-modal-${index}`"> + <gl-dropdown-item + v-if="alertWidgetAvailable" + v-gl-modal="`alert-modal-${index}`" + data-qa-selector="alert_widget_menu_item" + > {{ __('Alerts') }} </gl-dropdown-item> </gl-dropdown> diff --git a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue index afb8439511f..33f5199aabe 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue @@ -331,6 +331,7 @@ export default { :loading="isRetrying" :disabled="isRetrying" container-class="js-pipelines-retry-button btn btn-default btn-retry" + data-qa-selector="pipeline_retry_button" @click="handleRetryClick" > <icon name="repeat" /> diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb index 8c8f0b3a22e..6f0c7abac16 100644 --- a/app/controllers/concerns/authenticates_with_two_factor.rb +++ b/app/controllers/concerns/authenticates_with_two_factor.rb @@ -21,21 +21,28 @@ module AuthenticatesWithTwoFactor # Set @user for Devise views @user = user # rubocop:disable Gitlab/ModuleWithInstanceVariables - return locked_user_redirect(user) unless user.can?(:log_in) + return handle_locked_user(user) unless user.can?(:log_in) session[:otp_user_id] = user.id setup_u2f_authentication(user) render 'devise/sessions/two_factor' end + def handle_locked_user(user) + clear_two_factor_attempt! + + locked_user_redirect(user) + end + def locked_user_redirect(user) - flash.now[:alert] = _('Invalid Login or password') + flash.now[:alert] = locked_user_redirect_alert(user) + render 'devise/sessions/new' end def authenticate_with_two_factor user = self.resource = find_user - return locked_user_redirect(user) unless user.can?(:log_in) + return handle_locked_user(user) unless user.can?(:log_in) if user_params[:otp_attempt].present? && session[:otp_user_id] authenticate_with_two_factor_via_otp(user) @@ -48,6 +55,14 @@ module AuthenticatesWithTwoFactor private + def locked_user_redirect_alert(user) + user.access_locked? ? _('Your account is locked.') : _('Invalid Login or password') + end + + def clear_two_factor_attempt! + session.delete(:otp_user_id) + end + def authenticate_with_two_factor_via_otp(user) if valid_otp_attempt?(user) # Remove any lingering user data from login diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml index e8dd467c7ff..c2ac00e012a 100644 --- a/app/views/layouts/nav/sidebar/_project.html.haml +++ b/app/views/layouts/nav/sidebar/_project.html.haml @@ -240,7 +240,7 @@ - if project_nav_tab? :environments = nav_link(controller: :environments, action: [:metrics, :metrics_redirect]) do - = link_to metrics_project_environments_path(@project), title: _('Metrics'), class: 'shortcuts-metrics' do + = link_to metrics_project_environments_path(@project), title: _('Metrics'), class: 'shortcuts-metrics', data: { qa_selector: 'operations_metrics_link' } do %span = _('Metrics') diff --git a/doc/user/project/milestones/index.md b/doc/user/project/milestones/index.md index 82a63b07d6b..89c5522f4c4 100644 --- a/doc/user/project/milestones/index.md +++ b/doc/user/project/milestones/index.md @@ -64,7 +64,7 @@ You can delete a milestone by clicking the **Delete** button. ### Promoting project milestones to group milestones -If you are expanding from a few projects to a larger number of projects within the same group, you may want to share the same milestone among multiple projects in the same group. If you previously created a project milestone and now want to make it available for other milestones, you can promote it to a group milestone. +If you are expanding from a few projects to a larger number of projects within the same group, you may want to share the same milestone among multiple projects in the same group. If you previously created a project milestone and now want to make it available for other projects within the same group, you can promote it to a group milestone. From the project milestone list page, you can promote a project milestone to a group milestone. This will merge all project milestones across all projects in this group with the same name into a single group milestones. All issues and merge requests that previously were assigned one of these project milestones will now be assigned the new group milestones. This action cannot be reversed and the changes are permanent. diff --git a/lib/gitlab/diff/deprecated_highlight_cache.rb b/lib/gitlab/diff/deprecated_highlight_cache.rb deleted file mode 100644 index 47347686973..00000000000 --- a/lib/gitlab/diff/deprecated_highlight_cache.rb +++ /dev/null @@ -1,68 +0,0 @@ -# frozen_string_literal: true -# -module Gitlab - module Diff - class DeprecatedHighlightCache - delegate :diffable, to: :@diff_collection - delegate :diff_options, to: :@diff_collection - - def initialize(diff_collection, backend: Rails.cache) - @backend = backend - @diff_collection = diff_collection - end - - # - Reads from cache - # - Assigns DiffFile#highlighted_diff_lines for cached files - def decorate(diff_file) - if content = read_file(diff_file) - diff_file.highlighted_diff_lines = content.map do |line| - Gitlab::Diff::Line.init_from_hash(line) - end - end - end - - # It populates a Hash in order to submit a single write to the memory - # cache. This avoids excessive IO generated by N+1's (1 writing for - # each highlighted line or file). - def write_if_empty - return if cached_content.present? - - @diff_collection.diff_files.each do |diff_file| - next unless cacheable?(diff_file) - - diff_file_id = diff_file.file_identifier - - cached_content[diff_file_id] = diff_file.highlighted_diff_lines.map(&:to_hash) - end - - cache.write(key, cached_content, expires_in: 1.week) - end - - def clear - cache.delete(key) - end - - def key - [diffable, 'highlighted-diff-files', Gitlab::Diff::Line::SERIALIZE_KEYS, diff_options] - end - - private - - def read_file(diff_file) - cached_content[diff_file.file_identifier] - end - - def cache - @backend - end - - def cached_content - @cached_content ||= cache.read(key) || {} - end - - def cacheable?(diff_file) - diffable.present? && diff_file.text? && diff_file.diffable? - end - end - end -end diff --git a/lib/gitlab/diff/highlight_cache.rb b/lib/gitlab/diff/highlight_cache.rb index 403effbb0c6..a3d88664bac 100644 --- a/lib/gitlab/diff/highlight_cache.rb +++ b/lib/gitlab/diff/highlight_cache.rb @@ -57,17 +57,6 @@ module Gitlab private - # We create a Gitlab::Diff::DeprecatedHighlightCache here in order to - # expire deprecated cache entries while we make the transition. This can - # be removed when :hset_redis_diff_caching is fully launched. - # See https://gitlab.com/gitlab-org/gitlab/issues/38008 - # - def deprecated_cache - strong_memoize(:deprecated_cache) do - Gitlab::Diff::DeprecatedHighlightCache.new(@diff_collection) - end - end - def cacheable_files strong_memoize(:cacheable_files) do diff_files.select { |file| cacheable?(file) && read_file(file).nil? } @@ -104,10 +93,6 @@ module Gitlab # clear_memoization(:cached_content) clear_memoization(:cacheable_files) - - # Clean up any deprecated hash entries - # - deprecated_cache.clear end def file_paths diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 155adebe6cf..d51264bd425 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -21925,6 +21925,9 @@ msgstr "" msgid "Your account has been deactivated by your administrator. Please log back in to reactivate your account." msgstr "" +msgid "Your account is locked." +msgstr "" + msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO." msgstr "" @@ -289,6 +289,8 @@ module QA autoload :AddExisting, 'qa/page/project/operations/kubernetes/add_existing' autoload :Show, 'qa/page/project/operations/kubernetes/show' end + + autoload :Metrics, 'qa/page/project/operations/metrics' end module Wiki diff --git a/qa/qa/fixtures/monitored_auto_devops/.gitlab-ci.yml b/qa/qa/fixtures/monitored_auto_devops/.gitlab-ci.yml new file mode 100644 index 00000000000..a65ae5aa1d9 --- /dev/null +++ b/qa/qa/fixtures/monitored_auto_devops/.gitlab-ci.yml @@ -0,0 +1,337 @@ +# This is stripped down version of the .gitlab-ci.yml found +# here: https://gitlab.com/joshlambert/autodevops-deploy. +# +# It performs only the deploy stage. + +image: alpine:latest + +variables: + # AUTO_DEVOPS_DOMAIN is the application deployment domain and should be set as a variable at the group or project level. + AUTO_DEVOPS_DOMAIN: my-fake-domain.com + + POSTGRES_USER: user + POSTGRES_PASSWORD: testing-password + POSTGRES_ENABLED: 'false' + POSTGRES_DB: $CI_ENVIRONMENT_SLUG + + KUBERNETES_VERSION: 1.11.6 + HELM_VERSION: 2.12.2 + + DOCKER_DRIVER: overlay2 + +stages: + - production + +# This job continuously deploys to production on every push to `master`. + +production: + stage: production + script: + - check_kube_domain + - install_dependencies + - download_chart + - ensure_namespace + - initialize_tiller + - create_secret + - deploy + - persist_environment_url + environment: + name: production + url: http://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN + artifacts: + paths: [environment_url.txt] + only: + refs: + - master + kubernetes: active + +# --------------------------------------------------------------------------- + +.auto_devops: &auto_devops | + # Auto DevOps variables and functions + [[ "$TRACE" ]] && set -x + auto_database_url=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${CI_ENVIRONMENT_SLUG}-postgres:5432/${POSTGRES_DB} + export DATABASE_URL=${DATABASE_URL-$auto_database_url} + export CI_APPLICATION_REPOSITORY=$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG + export CI_APPLICATION_TAG=$CI_COMMIT_SHA + export CI_CONTAINER_NAME=ci_job_build_${CI_JOB_ID} + export TILLER_NAMESPACE=$KUBE_NAMESPACE + # Extract "MAJOR.MINOR" from CI_SERVER_VERSION and generate "MAJOR-MINOR-stable" for Security Products + export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') + + + function get_replicas() { + track="${1:-stable}" + percentage="${2:-100}" + + env_track=$( echo $track | tr -s '[:lower:]' '[:upper:]' ) + env_slug=$( echo ${CI_ENVIRONMENT_SLUG//-/_} | tr -s '[:lower:]' '[:upper:]' ) + + if [[ "$track" == "stable" ]] || [[ "$track" == "rollout" ]]; then + # for stable track get number of replicas from `PRODUCTION_REPLICAS` + eval new_replicas=\$${env_slug}_REPLICAS + if [[ -z "$new_replicas" ]]; then + new_replicas=$REPLICAS + fi + else + # for all tracks get number of replicas from `CANARY_PRODUCTION_REPLICAS` + eval new_replicas=\$${env_track}_${env_slug}_REPLICAS + if [[ -z "$new_replicas" ]]; then + eval new_replicas=\${env_track}_REPLICAS + fi + fi + + replicas="${new_replicas:-1}" + replicas="$(($replicas * $percentage / 100))" + + # always return at least one replicas + if [[ $replicas -gt 0 ]]; then + echo "$replicas" + else + echo 1 + fi + } + + + # Extracts variables prefixed with K8S_SECRET_ + # and creates a Kubernetes secret. + # + # e.g. If we have the following environment variables: + # K8S_SECRET_A=value1 + # K8S_SECRET_B=multi\ word\ value + # + # Then we will create a secret with the following key-value pairs: + # data: + # A: dmFsdWUxCg== + # B: bXVsdGkgd29yZCB2YWx1ZQo= + function create_application_secret() { + track="${1-stable}" + export APPLICATION_SECRET_NAME=$(application_secret_name "$track") + + env | sed -n "s/^K8S_SECRET_\(.*\)$/\1/p" > k8s_prefixed_variables + + kubectl create secret \ + -n "$KUBE_NAMESPACE" generic "$APPLICATION_SECRET_NAME" \ + --from-env-file k8s_prefixed_variables -o yaml --dry-run | + kubectl replace -n "$KUBE_NAMESPACE" --force -f - + + export APPLICATION_SECRET_CHECKSUM=$(cat k8s_prefixed_variables | sha256sum | cut -d ' ' -f 1) + + rm k8s_prefixed_variables + } + + function deploy_name() { + name="$CI_ENVIRONMENT_SLUG" + track="${1-stable}" + + if [[ "$track" != "stable" ]]; then + name="$name-$track" + fi + + echo $name + } + + function application_secret_name() { + track="${1-stable}" + name=$(deploy_name "$track") + + echo "${name}-secret" + } + + + function deploy() { + track="${1-stable}" + percentage="${2:-100}" + name=$(deploy_name "$track") + + replicas="1" + service_enabled="true" + postgres_enabled="$POSTGRES_ENABLED" + + # if track is different than stable, + # re-use all attached resources + if [[ "$track" != "stable" ]]; then + service_enabled="false" + postgres_enabled="false" + fi + + replicas=$(get_replicas "$track" "$percentage") + + if [[ "$CI_PROJECT_VISIBILITY" != "public" ]]; then + secret_name='gitlab-registry' + else + secret_name='' + fi + + create_application_secret "$track" + + env_slug=$(echo ${CI_ENVIRONMENT_SLUG//-/_} | tr -s '[:lower:]' '[:upper:]') + eval env_ADDITIONAL_HOSTS=\$${env_slug}_ADDITIONAL_HOSTS + if [ -n "$env_ADDITIONAL_HOSTS" ]; then + additional_hosts="{$env_ADDITIONAL_HOSTS}" + elif [ -n "$ADDITIONAL_HOSTS" ]; then + additional_hosts="{$ADDITIONAL_HOSTS}" + fi + + if [[ -n "$DB_INITIALIZE" && -z "$(helm ls -q "^$name$")" ]]; then + echo "Deploying first release with database initialization..." + helm upgrade --install \ + --wait \ + --set service.enabled="$service_enabled" \ + --set releaseOverride="$CI_ENVIRONMENT_SLUG" \ + --set image.repository="registry.gitlab.com/joshlambert/ruby-gke/master" \ + --set image.tag="63492726c2264a0277141d6a6573c3d22ecd7de3" \ + --set image.pullPolicy=IfNotPresent \ + --set image.secrets[0].name="$secret_name" \ + --set application.track="$track" \ + --set application.database_url="$DATABASE_URL" \ + --set application.secretName="$APPLICATION_SECRET_NAME" \ + --set application.secretChecksum="$APPLICATION_SECRET_CHECKSUM" \ + --set service.url="$CI_ENVIRONMENT_URL" \ + --set service.additionalHosts="$additional_hosts" \ + --set replicaCount="$replicas" \ + --set postgresql.enabled="$postgres_enabled" \ + --set postgresql.nameOverride="postgres" \ + --set postgresql.postgresUser="$POSTGRES_USER" \ + --set postgresql.postgresPassword="$POSTGRES_PASSWORD" \ + --set postgresql.postgresDatabase="$POSTGRES_DB" \ + --set application.initializeCommand="$DB_INITIALIZE" \ + --set gitlab.app="$CI_PROJECT_PATH_SLUG" \ + --set gitlab.env="$CI_ENVIRONMENT_SLUG" \ + --namespace="$KUBE_NAMESPACE" \ + "$name" \ + chart/ + + echo "Deploying second release..." + helm upgrade --reuse-values \ + --wait \ + --set application.initializeCommand="" \ + --set application.migrateCommand="$DB_MIGRATE" \ + --namespace="$KUBE_NAMESPACE" \ + "$name" \ + chart/ + else + echo "Deploying new release..." + helm upgrade --install \ + --wait \ + --set service.enabled="$service_enabled" \ + --set releaseOverride="$CI_ENVIRONMENT_SLUG" \ + --set image.repository="registry.gitlab.com/joshlambert/ruby-gke/master" \ + --set image.tag="63492726c2264a0277141d6a6573c3d22ecd7de3" \ + --set image.pullPolicy=IfNotPresent \ + --set image.secrets[0].name="$secret_name" \ + --set application.track="$track" \ + --set application.database_url="$DATABASE_URL" \ + --set application.secretName="$APPLICATION_SECRET_NAME" \ + --set application.secretChecksum="$APPLICATION_SECRET_CHECKSUM" \ + --set service.url="$CI_ENVIRONMENT_URL" \ + --set service.additionalHosts="$additional_hosts" \ + --set replicaCount="$replicas" \ + --set postgresql.enabled="$postgres_enabled" \ + --set postgresql.nameOverride="postgres" \ + --set postgresql.postgresUser="$POSTGRES_USER" \ + --set postgresql.postgresPassword="$POSTGRES_PASSWORD" \ + --set postgresql.postgresDatabase="$POSTGRES_DB" \ + --set application.migrateCommand="$DB_MIGRATE" \ + --set gitlab.app="$CI_PROJECT_PATH_SLUG" \ + --set gitlab.env="$CI_ENVIRONMENT_SLUG" \ + --namespace="$KUBE_NAMESPACE" \ + "$name" \ + chart/ + fi + + kubectl rollout status -n "$KUBE_NAMESPACE" -w "deployment/$name" + } + + + function install_dependencies() { + apk add -U openssl curl tar gzip bash ca-certificates git + wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub + wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.23-r3/glibc-2.23-r3.apk + apk add glibc-2.23-r3.apk + rm glibc-2.23-r3.apk + + curl "https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz" | tar zx + mv linux-amd64/helm /usr/bin/ + mv linux-amd64/tiller /usr/bin/ + helm version --client + tiller -version + + curl -L -o /usr/bin/kubectl "https://storage.googleapis.com/kubernetes-release/release/v${KUBERNETES_VERSION}/bin/linux/amd64/kubectl" + chmod +x /usr/bin/kubectl + kubectl version --client + } + + function download_chart() { + if [[ ! -d chart ]]; then + auto_chart=${AUTO_DEVOPS_CHART:-gitlab/auto-deploy-app} + auto_chart_name=$(basename $auto_chart) + auto_chart_name=${auto_chart_name%.tgz} + else + auto_chart="chart" + auto_chart_name="chart" + fi + + helm init --client-only + helm repo add gitlab https://charts.gitlab.io + if [[ ! -d "$auto_chart" ]]; then + helm fetch ${auto_chart} --untar + fi + if [ "$auto_chart_name" != "chart" ]; then + mv ${auto_chart_name} chart + fi + + helm dependency update chart/ + helm dependency build chart/ + } + + function ensure_namespace() { + kubectl describe namespace "$KUBE_NAMESPACE" || kubectl create namespace "$KUBE_NAMESPACE" + } + + function check_kube_domain() { + if [ -z ${AUTO_DEVOPS_DOMAIN+x} ]; then + echo "In order to deploy or use Review Apps, AUTO_DEVOPS_DOMAIN variable must be set" + echo "You can do it in Auto DevOps project settings or defining a secret variable at group or project level" + echo "You can also manually add it in .gitlab-ci.yml" + false + else + true + fi + } + + function initialize_tiller() { + echo "Checking Tiller..." + + export HELM_HOST="localhost:44134" + tiller -listen ${HELM_HOST} -alsologtostderr > /dev/null 2>&1 & + echo "Tiller is listening on ${HELM_HOST}" + + if ! helm version --debug; then + echo "Failed to init Tiller." + return 1 + fi + echo "" + } + + function create_secret() { + echo "Create secret..." + if [[ "$CI_PROJECT_VISIBILITY" == "public" ]]; then + return + fi + + kubectl create secret -n "$KUBE_NAMESPACE" \ + docker-registry gitlab-registry \ + --docker-server="$CI_REGISTRY" \ + --docker-username="$CI_REGISTRY_USER" \ + --docker-password="$CI_REGISTRY_PASSWORD" \ + --docker-email="$GITLAB_USER_EMAIL" \ + -o yaml --dry-run | kubectl replace -n "$KUBE_NAMESPACE" --force -f - + } + + function persist_environment_url() { + echo $CI_ENVIRONMENT_URL > environment_url.txt + } + +before_script: + - *auto_devops diff --git a/qa/qa/page/project/operations/metrics.rb b/qa/qa/page/project/operations/metrics.rb new file mode 100644 index 00000000000..418cc925186 --- /dev/null +++ b/qa/qa/page/project/operations/metrics.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module QA + module Page + module Project + module Operations + class Metrics < Page::Base + EXPECTED_TITLE = 'Memory Usage (Total)' + LOADING_MESSAGE = 'Waiting for performance data' + + view 'app/assets/javascripts/monitoring/components/dashboard.vue' do + element :prometheus_graphs + end + + view 'app/assets/javascripts/monitoring/components/charts/time_series.vue' do + element :prometheus_graph_widgets + end + + view 'app/assets/javascripts/monitoring/components/panel_type.vue' do + element :prometheus_widgets_dropdown + element :alert_widget_menu_item + end + + def wait_for_metrics + wait_for_data + return if has_metrics? + + wait_until(max_duration: 180) do + wait_for_data + has_metrics? + end + end + + def wait_for_data + wait_until(reload: false) { !has_text?(LOADING_MESSAGE) } if has_text?(LOADING_MESSAGE) + end + + def has_metrics? + within_element :prometheus_graphs do + has_text?(EXPECTED_TITLE) + end + end + end + end + end + end +end + +QA::Page::Project::Operations::Metrics.prepend_if_ee('QA::EE::Page::Project::Operations::Metrics') diff --git a/qa/qa/page/project/pipeline/index.rb b/qa/qa/page/project/pipeline/index.rb index 684ad4a59d5..f018e4bf018 100644 --- a/qa/qa/page/project/pipeline/index.rb +++ b/qa/qa/page/project/pipeline/index.rb @@ -9,6 +9,7 @@ module QA::Page view 'app/assets/javascripts/pipelines/components/pipelines_table_row.vue' do element :pipeline_commit_status + element :pipeline_retry_button end def click_on_latest_pipeline @@ -18,10 +19,25 @@ module QA::Page end def wait_for_latest_pipeline_success + wait_for_latest_pipeline_status { has_text?('passed') } + end + + def wait_for_latest_pipeline_completion + wait_for_latest_pipeline_status { has_text?('passed') || has_text?('failed') } + end + + def wait_for_latest_pipeline_status wait_until(reload: false, max_duration: 300) do - within_element_by_index(:pipeline_commit_status, 0) do - has_text?('passed') - end + within_element_by_index(:pipeline_commit_status, 0) { yield } + end + end + + def wait_for_latest_pipeline_success_or_retry + wait_for_latest_pipeline_completion + + if has_text?('failed') + click_element :pipeline_retry_button + wait_for_latest_pipeline_success end end end diff --git a/qa/qa/page/project/sub_menus/operations.rb b/qa/qa/page/project/sub_menus/operations.rb index d266cb21417..bcbc1dc16d3 100644 --- a/qa/qa/page/project/sub_menus/operations.rb +++ b/qa/qa/page/project/sub_menus/operations.rb @@ -12,6 +12,7 @@ module QA view 'app/views/layouts/nav/sidebar/_project.html.haml' do element :link_operations element :operations_environments_link + element :operations_metrics_link end end end @@ -24,6 +25,14 @@ module QA end end + def go_to_operations_metrics + hover_operations do + within_submenu do + click_element(:operations_metrics_link) + end + end + end + def go_to_operations_kubernetes hover_operations do within_submenu do diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index 63797e22b38..2f597fd5cb3 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -394,8 +394,7 @@ describe SessionsController do end it 'warns about invalid login' do - expect(response).to set_flash.now[:alert] - .to /Invalid Login or password/ + expect(response).to set_flash.now[:alert].to /Your account is locked./ end it 'locks the user' do @@ -405,8 +404,7 @@ describe SessionsController do it 'keeps the user locked on future login attempts' do post(:create, params: { user: { login: user.username, password: user.password } }) - expect(response) - .to set_flash.now[:alert].to /Invalid Login or password/ + expect(response).to set_flash.now[:alert].to /Your account is locked./ end end end diff --git a/spec/lib/gitlab/diff/deprecated_highlight_cache_spec.rb b/spec/lib/gitlab/diff/deprecated_highlight_cache_spec.rb deleted file mode 100644 index 7e46632ea77..00000000000 --- a/spec/lib/gitlab/diff/deprecated_highlight_cache_spec.rb +++ /dev/null @@ -1,70 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Gitlab::Diff::DeprecatedHighlightCache do - let(:merge_request) { create(:merge_request_with_diffs) } - - subject(:cache) { described_class.new(merge_request.diffs, backend: backend) } - - describe '#decorate' do - let(:backend) { double('backend').as_null_object } - - # Manually creates a Diff::File object to avoid triggering the cache on - # the FileCollection::MergeRequestDiff - let(:diff_file) do - diffs = merge_request.diffs - raw_diff = diffs.diffable.raw_diffs(diffs.diff_options.merge(paths: ['CHANGELOG'])).first - Gitlab::Diff::File.new(raw_diff, - repository: diffs.project.repository, - diff_refs: diffs.diff_refs, - fallback_diff_refs: diffs.fallback_diff_refs) - end - - it 'does not calculate highlighting when reading from cache' do - cache.write_if_empty - cache.decorate(diff_file) - - expect_any_instance_of(Gitlab::Diff::Highlight).not_to receive(:highlight) - - diff_file.highlighted_diff_lines - end - - it 'assigns highlighted diff lines to the DiffFile' do - cache.write_if_empty - cache.decorate(diff_file) - - expect(diff_file.highlighted_diff_lines.size).to be > 5 - end - - it 'submits a single reading from the cache' do - cache.decorate(diff_file) - cache.decorate(diff_file) - - expect(backend).to have_received(:read).with(cache.key).once - end - end - - describe '#write_if_empty' do - let(:backend) { double('backend', read: {}).as_null_object } - - it 'submits a single writing to the cache' do - cache.write_if_empty - cache.write_if_empty - - expect(backend).to have_received(:write).with(cache.key, - hash_including('CHANGELOG-false-false-false'), - expires_in: 1.week).once - end - end - - describe '#clear' do - let(:backend) { double('backend').as_null_object } - - it 'clears cache' do - cache.clear - - expect(backend).to have_received(:delete).with(cache.key) - end - end -end diff --git a/spec/lib/gitlab/diff/highlight_cache_spec.rb b/spec/lib/gitlab/diff/highlight_cache_spec.rb index c73ec84e332..bff51709c40 100644 --- a/spec/lib/gitlab/diff/highlight_cache_spec.rb +++ b/spec/lib/gitlab/diff/highlight_cache_spec.rb @@ -135,16 +135,6 @@ describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do expect { cache.send(:write_to_redis_hash, diff_hash) } .to change { Gitlab::Redis::Cache.with { |r| r.hgetall(cache_key) } } end - - # Note that this spec and the code it confirms can be removed when - # :hset_redis_diff_caching is fully launched. - # - it 'attempts to clear deprecated cache entries' do - expect_any_instance_of(Gitlab::Diff::DeprecatedHighlightCache) - .to receive(:clear).and_call_original - - cache.send(:write_to_redis_hash, diff_hash) - end end describe '#clear' do |