diff --git a/app/assets/javascripts/error_tracking/components/error_details.vue b/app/assets/javascripts/error_tracking/components/error_details.vue index 37c9818f869..ab782f955c6 100644 --- a/app/assets/javascripts/error_tracking/components/error_details.vue +++ b/app/assets/javascripts/error_tracking/components/error_details.vue @@ -32,6 +32,10 @@ export default { type: String, required: true, }, + issueProjectPath: { + type: String, + required: true, + }, }, computed: { ...mapState('details', ['error', 'loading', 'loadingStacktrace', 'stacktraceData']), @@ -82,9 +86,9 @@ export default {
- + + {{ __('Create issue') }} +
diff --git a/app/assets/javascripts/error_tracking/details.js b/app/assets/javascripts/error_tracking/details.js index b9b51a6539f..435315842bd 100644 --- a/app/assets/javascripts/error_tracking/details.js +++ b/app/assets/javascripts/error_tracking/details.js @@ -12,12 +12,13 @@ export default () => { store, render(createElement) { const domEl = document.querySelector(this.$options.el); - const { issueDetailsPath, issueStackTracePath } = domEl.dataset; + const { issueDetailsPath, issueStackTracePath, issueProjectPath } = domEl.dataset; return createElement('error-details', { props: { issueDetailsPath, issueStackTracePath, + issueProjectPath, }, }); }, diff --git a/app/helpers/projects/error_tracking_helper.rb b/app/helpers/projects/error_tracking_helper.rb index c31e16e7150..2dd22402028 100644 --- a/app/helpers/projects/error_tracking_helper.rb +++ b/app/helpers/projects/error_tracking_helper.rb @@ -18,6 +18,7 @@ module Projects::ErrorTrackingHelper opts = [project, issue_id, { format: :json }] { + 'issue-project-path' => new_project_issue_path(project), 'issue-details-path' => details_project_error_tracking_index_path(*opts), 'issue-stack-trace-path' => stack_trace_project_error_tracking_index_path(*opts) } diff --git a/app/views/admin/sessions/_new_base.html.haml b/app/views/admin/sessions/_new_base.html.haml index 3d77a439d61..50fa48855c0 100644 --- a/app/views/admin/sessions/_new_base.html.haml +++ b/app/views/admin/sessions/_new_base.html.haml @@ -4,4 +4,4 @@ = password_field_tag :password, nil, class: 'form-control', required: true, title: _('This field is required.'), data: { qa_selector: 'password_field' } .submit-container.move-submit-down - = submit_tag _('Enter Admin Mode'), class: 'btn btn-success', data: { qa_selector: 'sign_in_button' } + = submit_tag _('Enter Admin Mode'), class: 'btn btn-success', data: { qa_selector: 'enter_admin_mode_button' } diff --git a/changelogs/unreleased/lm-create-new-issue-from-sentry.yml b/changelogs/unreleased/lm-create-new-issue-from-sentry.yml new file mode 100644 index 00000000000..31a6a5eb4cc --- /dev/null +++ b/changelogs/unreleased/lm-create-new-issue-from-sentry.yml @@ -0,0 +1,5 @@ +--- +title: Add ability to create new issue from sentry error detail page +merge_request: 20337 +author: +type: added diff --git a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml index c81b4efddbc..75594eeb619 100644 --- a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml @@ -6,9 +6,10 @@ variables: SAST_ANALYZER_IMAGE_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers" - SAST_DEFAULT_ANALYZERS: "bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, tslint, secrets, sobelow, pmd-apex" + SAST_DEFAULT_ANALYZERS: "bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, tslint, secrets, sobelow, pmd-apex, kubesec" SAST_ANALYZER_IMAGE_TAG: 2 SAST_DISABLE_DIND: "false" + SCAN_KUBERNETES_MANIFESTS: "false" sast: stage: test @@ -98,6 +99,16 @@ flawfinder-sast: $SAST_DEFAULT_ANALYZERS =~ /flawfinder/ && $CI_PROJECT_REPOSITORY_LANGUAGES =~ /\b(c\+\+|c)\b/ +kubesec-sast: + extends: .analyzer + image: + name: "$SAST_ANALYZER_IMAGE_PREFIX/kubesec:$SAST_ANALYZER_IMAGE_TAG" + only: + variables: + - $GITLAB_FEATURES =~ /\bsast\b/ && + $SAST_DEFAULT_ANALYZERS =~ /kubesec/ && + $SCAN_KUBERNETES_MANIFESTS == 'true' + gosec-sast: extends: .analyzer image: diff --git a/locale/gitlab.pot b/locale/gitlab.pot index fbd58f02027..e82d513a99a 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -4892,6 +4892,9 @@ msgstr "" msgid "Create group label" msgstr "" +msgid "Create issue" +msgstr "" + msgid "Create lists from labels. Issues with that label appear in that list." msgstr "" diff --git a/qa/qa.rb b/qa/qa.rb index 6397e4216d9..902963a6ed2 100644 --- a/qa/qa.rb +++ b/qa/qa.rb @@ -331,6 +331,7 @@ module QA module Admin autoload :Menu, 'qa/page/admin/menu' + autoload :NewSession, 'qa/page/admin/new_session' module Settings autoload :Repository, 'qa/page/admin/settings/repository' diff --git a/qa/qa/page/admin/new_session.rb b/qa/qa/page/admin/new_session.rb new file mode 100644 index 00000000000..3d46bb7f186 --- /dev/null +++ b/qa/qa/page/admin/new_session.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module QA + module Page + module Admin + class NewSession < Page::Base + view 'app/views/admin/sessions/_new_base.html.haml' do + element :enter_admin_mode_button + element :password_field + end + + def set_password(password) + fill_element :password_field, password + end + + def click_enter_admin_mode + click_element :enter_admin_mode_button + end + end + end + end +end diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb index ed4d33dc7a3..a080c4071ed 100644 --- a/qa/qa/page/base.rb +++ b/qa/qa/page/base.rb @@ -86,11 +86,19 @@ module QA end def check_element(name) - find_element(name).set(true) + retry_until(sleep_interval: 1) do + find_element(name).set(true) + + find_element(name).checked? + end end def uncheck_element(name) - find_element(name).set(false) + retry_until(sleep_interval: 1) do + find_element(name).set(false) + + !find_element(name).checked? + end end # replace with (..., page = self.class) @@ -125,8 +133,8 @@ module QA has_no_css?(element_selector_css(name, kwargs), wait: wait, text: text) end - def has_text?(text) - page.has_text? text + def has_text?(text, wait: Capybara.default_max_wait_time) + page.has_text?(text, wait: wait) end def has_no_text?(text) diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb index 49c48568e68..5f4b3946e6a 100644 --- a/qa/qa/page/main/menu.rb +++ b/qa/qa/page/main/menu.rb @@ -60,8 +60,15 @@ module QA end end - def click_admin_area - within_top_menu { click_element :admin_area_link } + def go_to_admin_area + click_admin_area + + if has_text?('Enter Admin Mode', wait: 1.0) + Admin::NewSession.perform do |new_session| + new_session.set_password(Runtime::User.admin_password) + new_session.click_enter_admin_mode + end + end end def signed_in? @@ -125,6 +132,10 @@ module QA end end end + + def click_admin_area + within_top_menu { click_element :admin_area_link } + end end end end diff --git a/qa/qa/resource/settings/hashed_storage.rb b/qa/qa/resource/settings/hashed_storage.rb index 08bb95cfd4b..40c06768ffe 100644 --- a/qa/qa/resource/settings/hashed_storage.rb +++ b/qa/qa/resource/settings/hashed_storage.rb @@ -8,7 +8,7 @@ module QA raise ArgumentError unless traits.include?(:enabled) Page::Main::Login.perform(&:sign_in_using_credentials) - Page::Main::Menu.perform(&:click_admin_area) + Page::Main::Menu.perform(&:go_to_admin_area) Page::Admin::Menu.perform(&:go_to_repository_settings) Page::Admin::Settings::Repository.perform do |setting| diff --git a/qa/qa/runtime/api/client.rb b/qa/qa/runtime/api/client.rb index 83fbb8f15d2..4f9fb586ee3 100644 --- a/qa/qa/runtime/api/client.rb +++ b/qa/qa/runtime/api/client.rb @@ -32,7 +32,7 @@ module QA Runtime::Browser.visit(@address, Page::Main::Login) Page::Main::Login.perform(&:sign_in_using_admin_credentials) - Page::Main::Menu.perform(&:click_admin_area) + Page::Main::Menu.perform(&:go_to_admin_area) Page::Admin::Menu.perform(&:go_to_network_settings) Page::Admin::Settings::Network.perform do |setting| diff --git a/qa/qa/specs/features/browser_ui/non_devops/performance_bar_spec.rb b/qa/qa/specs/features/browser_ui/non_devops/performance_bar_spec.rb index 187c4a2a248..167a68dab00 100644 --- a/qa/qa/specs/features/browser_ui/non_devops/performance_bar_spec.rb +++ b/qa/qa/specs/features/browser_ui/non_devops/performance_bar_spec.rb @@ -6,7 +6,7 @@ module QA before do Runtime::Browser.visit(:gitlab, Page::Main::Login) Page::Main::Login.perform(&:sign_in_using_admin_credentials) - Page::Main::Menu.perform(&:click_admin_area) + Page::Main::Menu.perform(&:go_to_admin_area) Page::Admin::Menu.perform(&:go_to_metrics_and_profiling_settings) Page::Admin::Settings::MetricsAndProfiling.perform do |setting| diff --git a/qa/qa/support/page/logging.rb b/qa/qa/support/page/logging.rb index 6b6e12f86de..f1cb876222e 100644 --- a/qa/qa/support/page/logging.rb +++ b/qa/qa/support/page/logging.rb @@ -59,6 +59,18 @@ module QA elements end + def check_element(name) + log("checking :#{name}") + + super + end + + def uncheck_element(name) + log("unchecking :#{name}") + + super + end + def click_element(name, page = nil, **kwargs) msg = ["clicking :#{name}"] msg << ", expecting to be at #{page.class}" if page @@ -99,10 +111,10 @@ module QA found end - def has_text?(text) + def has_text?(text, **kwargs) found = super - log(%Q{has_text?('#{text}') returned #{found}}) + log(%Q{has_text?('#{text}', wait: #{kwargs[:wait] || Capybara.default_max_wait_time}) returned #{found}}) found end diff --git a/qa/spec/page/logging_spec.rb b/qa/spec/page/logging_spec.rb index 92a4f7b40e6..fb89bcd3ab4 100644 --- a/qa/spec/page/logging_spec.rb +++ b/qa/spec/page/logging_spec.rb @@ -117,7 +117,7 @@ describe QA::Support::Page::Logging do allow(page).to receive(:has_text?).and_return(true) expect { subject.has_text? 'foo' } - .to output(/has_text\?\('foo'\) returned true/).to_stdout_from_any_process + .to output(/has_text\?\('foo', wait: #{QA::Runtime::Browser::CAPYBARA_MAX_WAIT_TIME}\) returned true/).to_stdout_from_any_process end it 'logs has_no_text?' do diff --git a/spec/frontend/error_tracking/components/error_details_spec.js b/spec/frontend/error_tracking/components/error_details_spec.js index 54e8b0848a2..ddc17dea291 100644 --- a/spec/frontend/error_tracking/components/error_details_spec.js +++ b/spec/frontend/error_tracking/components/error_details_spec.js @@ -1,6 +1,6 @@ import { createLocalVue, shallowMount } from '@vue/test-utils'; import Vuex from 'vuex'; -import { GlLoadingIcon, GlLink } from '@gitlab/ui'; +import { GlButton, GlLoadingIcon, GlLink } from '@gitlab/ui'; import Stacktrace from '~/error_tracking/components/stacktrace.vue'; import ErrorDetails from '~/error_tracking/components/error_details.vue'; @@ -20,6 +20,7 @@ describe('ErrorDetails', () => { propsData: { issueDetailsPath: '/123/details', issueStackTracePath: '/stacktrace', + issueProjectPath: '/test-project/issues/new', }, }); } @@ -82,6 +83,15 @@ describe('ErrorDetails', () => { expect(wrapper.find(Stacktrace).exists()).toBe(false); }); + it('should allow a blank issue to be created', () => { + store.state.details.loading = false; + store.state.details.error.id = 1; + mountComponent(); + const button = wrapper.find(GlButton); + expect(button.exists()).toBe(true); + expect(button.attributes().href).toBe(wrapper.props().issueProjectPath); + }); + describe('Stacktrace', () => { it('should show stacktrace', () => { store.state.details.loading = false; diff --git a/spec/helpers/projects/error_tracking_helper_spec.rb b/spec/helpers/projects/error_tracking_helper_spec.rb index 5e7449e21b7..fdffdca22fb 100644 --- a/spec/helpers/projects/error_tracking_helper_spec.rb +++ b/spec/helpers/projects/error_tracking_helper_spec.rb @@ -81,6 +81,7 @@ describe Projects::ErrorTrackingHelper do let(:route_params) { [project.owner, project, issue_id, { format: :json }] } let(:details_path) { details_namespace_project_error_tracking_index_path(*route_params) } let(:stack_trace_path) { stack_trace_namespace_project_error_tracking_index_path(*route_params) } + let(:issue_project_path) { new_project_issue_path(project) } let(:result) { helper.error_details_data(project, issue_id) } @@ -91,5 +92,9 @@ describe Projects::ErrorTrackingHelper do it 'returns the correct stack trace path' do expect(result['issue-stack-trace-path']).to eq stack_trace_path end + + it 'returns the correct path for creating a new issue' do + expect(result['issue-project-path']).to eq issue_project_path + end end end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index f9a95a96de1..0db54599ede 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -506,7 +506,6 @@ describe ProjectsHelper do it 'returns the command to push to create project over SSH' do allow(Gitlab::CurrentSettings.current_application_settings).to receive(:enabled_git_access_protocol) { 'ssh' } - allow(Gitlab.config.gitlab_shell).to receive(:ssh_path_prefix).and_return('git@localhost:') expect(helper.push_to_create_project_command(user)).to eq("git push --set-upstream #{Gitlab.config.gitlab.user}@localhost:john/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)") end