diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-06 09:06:23 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-06 09:06:23 +0000 |
commit | d15180e00b209d0fbe3d8ce61b3af269aecdf7f5 (patch) | |
tree | e24bcc044a3e471811b91ade8a23120a27210c3f | |
parent | 505c40d537244b35807129ade0c577f752e9d564 (diff) | |
download | gitlab-ce-d15180e00b209d0fbe3d8ce61b3af269aecdf7f5.tar.gz |
Add latest changes from gitlab-org/gitlab@master
30 files changed, 599 insertions, 7 deletions
diff --git a/app/assets/javascripts/ide/components/preview/clientside.vue b/app/assets/javascripts/ide/components/preview/clientside.vue index 6999746f115..beb179d0411 100644 --- a/app/assets/javascripts/ide/components/preview/clientside.vue +++ b/app/assets/javascripts/ide/components/preview/clientside.vue @@ -92,6 +92,7 @@ export default { }, methods: { ...mapActions(['getFileData', 'getRawFileData']), + ...mapActions('clientside', ['pingUsage']), loadFileContent(path) { return this.getFileData({ path, makeFileActive: false }).then(() => this.getRawFileData({ path }), @@ -100,6 +101,8 @@ export default { initPreview() { if (!this.mainEntry) return null; + this.pingUsage(); + return this.loadFileContent(this.mainEntry) .then(() => this.$nextTick()) .then(() => { diff --git a/app/assets/javascripts/ide/stores/index.js b/app/assets/javascripts/ide/stores/index.js index f1f544b52b2..85550578e94 100644 --- a/app/assets/javascripts/ide/stores/index.js +++ b/app/assets/javascripts/ide/stores/index.js @@ -10,6 +10,7 @@ import mergeRequests from './modules/merge_requests'; import branches from './modules/branches'; import fileTemplates from './modules/file_templates'; import paneModule from './modules/pane'; +import clientsideModule from './modules/clientside'; Vue.use(Vuex); @@ -26,6 +27,7 @@ export const createStore = () => branches, fileTemplates: fileTemplates(), rightPane: paneModule(), + clientside: clientsideModule(), }, }); diff --git a/app/assets/javascripts/ide/stores/modules/clientside/actions.js b/app/assets/javascripts/ide/stores/modules/clientside/actions.js new file mode 100644 index 00000000000..eb3bcdff2ae --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/clientside/actions.js @@ -0,0 +1,12 @@ +import axios from '~/lib/utils/axios_utils'; + +export const pingUsage = ({ rootGetters }) => { + const { web_url: projectUrl } = rootGetters.currentProject; + + const url = `${projectUrl}/usage_ping/web_ide_clientside_preview`; + + return axios.post(url); +}; + +// prevent babel-plugin-rewire from generating an invalid default during karma tests +export default () => {}; diff --git a/app/assets/javascripts/ide/stores/modules/clientside/index.js b/app/assets/javascripts/ide/stores/modules/clientside/index.js new file mode 100644 index 00000000000..b28f7b935a8 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/clientside/index.js @@ -0,0 +1,6 @@ +import * as actions from './actions'; + +export default () => ({ + namespaced: true, + actions, +}); diff --git a/app/controllers/projects/usage_ping_controller.rb b/app/controllers/projects/usage_ping_controller.rb new file mode 100644 index 00000000000..ebdf28bd59c --- /dev/null +++ b/app/controllers/projects/usage_ping_controller.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class Projects::UsagePingController < Projects::ApplicationController + before_action :authenticate_user! + + def web_ide_clientside_preview + return render_404 unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled? + + Gitlab::UsageDataCounters::WebIdeCounter.increment_previews_count + + head(200) + end +end diff --git a/app/models/concerns/storage/legacy_namespace.rb b/app/models/concerns/storage/legacy_namespace.rb index 78544405c49..ce98a3ad3d6 100644 --- a/app/models/concerns/storage/legacy_namespace.rb +++ b/app/models/concerns/storage/legacy_namespace.rb @@ -55,7 +55,7 @@ module Storage def move_repositories # Move the namespace directory in all storages used by member projects - repository_storages.each do |repository_storage| + repository_storages(legacy_only: true).each do |repository_storage| # Ensure old directory exists before moving it gitlab_shell.add_namespace(repository_storage, full_path_before_last_save) @@ -77,12 +77,14 @@ module Storage @old_repository_storage_paths ||= repository_storages end - def repository_storages + def repository_storages(legacy_only: false) # We need to get the storage paths for all the projects, even the ones that are # pending delete. Unscoping also get rids of the default order, which causes # problems with SELECT DISTINCT. Project.unscoped do - all_projects.select('distinct(repository_storage)').to_a.map(&:repository_storage) + namespace_projects = all_projects + namespace_projects = namespace_projects.without_storage_feature(:repository) if legacy_only + namespace_projects.pluck(Arel.sql('distinct(repository_storage)')) end end diff --git a/changelogs/unreleased/32398-geo-rake-gitlab-geo-check-on-the-primary-is-cluttered.yml b/changelogs/unreleased/32398-geo-rake-gitlab-geo-check-on-the-primary-is-cluttered.yml new file mode 100644 index 00000000000..e8a8828b929 --- /dev/null +++ b/changelogs/unreleased/32398-geo-rake-gitlab-geo-check-on-the-primary-is-cluttered.yml @@ -0,0 +1,5 @@ +--- +title: "[Geo] Fix: rake gitlab:geo:check on the primary is cluttered" +merge_request: 19460 +author: +type: changed diff --git a/changelogs/unreleased/add-slack-slash-command-issue-comment.yml b/changelogs/unreleased/add-slack-slash-command-issue-comment.yml new file mode 100644 index 00000000000..ccd82830303 --- /dev/null +++ b/changelogs/unreleased/add-slack-slash-command-issue-comment.yml @@ -0,0 +1,5 @@ +--- +title: Add a Slack slash command to add a comment to an issue +merge_request: 18946 +author: +type: added diff --git a/changelogs/unreleased/fj-24837-codesanbox-usage-ping.yml b/changelogs/unreleased/fj-24837-codesanbox-usage-ping.yml new file mode 100644 index 00000000000..480fdbd51f4 --- /dev/null +++ b/changelogs/unreleased/fj-24837-codesanbox-usage-ping.yml @@ -0,0 +1,5 @@ +--- +title: Add Codesandbox metrics to usage ping +merge_request: 19075 +author: +type: other diff --git a/changelogs/unreleased/jc-dont-try-to-movedirs-unless-legacy.yml b/changelogs/unreleased/jc-dont-try-to-movedirs-unless-legacy.yml new file mode 100644 index 00000000000..b1fd8a29a4f --- /dev/null +++ b/changelogs/unreleased/jc-dont-try-to-movedirs-unless-legacy.yml @@ -0,0 +1,5 @@ +--- +title: Only move repos for legacy project storage +merge_request: 19410 +author: +type: fixed diff --git a/config/routes/project.rb b/config/routes/project.rb index d628e1ea650..d49ba20ce84 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -617,6 +617,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do end end + scope :usage_ping, controller: :usage_ping do + post :web_ide_clientside_preview + end + # Since both wiki and repository routing contains wildcard characters # its preferable to keep it below all other project routes draw :wiki diff --git a/doc/integration/slash_commands.md b/doc/integration/slash_commands.md index b8842ef3a43..bc2f190920c 100644 --- a/doc/integration/slash_commands.md +++ b/doc/integration/slash_commands.md @@ -18,6 +18,7 @@ Taking the trigger term as `project-name`, the commands are: | `/project-name issue close <id>` | Closes the issue with id `<id>` | | `/project-name issue search <query>` | Shows up to 5 issues matching `<query>` | | `/project-name issue move <id> to <project>` | Moves issue ID `<id>` to `<project>` | +| `/project-name issue comment <id> <shift+return> <comment>` | Adds a new comment to an issue with id `<id>` and comment body `<comment>` | | `/project-name deploy <from> to <to>` | Deploy from the `<from>` environment to the `<to>` environment | | `/project-name run <job name> <arguments>` | Execute [ChatOps](../ci/chatops/README.md) job `<job name>` on `master` | diff --git a/lib/gitlab/slash_commands/command.rb b/lib/gitlab/slash_commands/command.rb index 079b5916566..239479f99d2 100644 --- a/lib/gitlab/slash_commands/command.rb +++ b/lib/gitlab/slash_commands/command.rb @@ -10,6 +10,7 @@ module Gitlab Gitlab::SlashCommands::IssueSearch, Gitlab::SlashCommands::IssueMove, Gitlab::SlashCommands::IssueClose, + Gitlab::SlashCommands::IssueComment, Gitlab::SlashCommands::Deploy, Gitlab::SlashCommands::Run ] diff --git a/lib/gitlab/slash_commands/issue_comment.rb b/lib/gitlab/slash_commands/issue_comment.rb new file mode 100644 index 00000000000..cbb9c41aab0 --- /dev/null +++ b/lib/gitlab/slash_commands/issue_comment.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module Gitlab + module SlashCommands + class IssueComment < IssueCommand + def self.match(text) + /\Aissue\s+comment\s+#{Issue.reference_prefix}?(?<iid>\d+)\n*(?<note_body>(.|\n)*)/.match(text) + end + + def self.help_message + 'issue comment <id> *`⇧ Shift`*+*`↵ Enter`* <comment>' + end + + def execute(match) + note_body = match[:note_body].to_s.strip + issue = find_by_iid(match[:iid]) + + return not_found unless issue + return access_denied unless can_create_note?(issue) + + note = create_note(issue: issue, note: note_body) + + if note.persisted? + presenter(note).present + else + presenter(note).display_errors + end + end + + private + + def can_create_note?(issue) + Ability.allowed?(current_user, :create_note, issue) + end + + def not_found + Gitlab::SlashCommands::Presenters::Access.new.not_found + end + + def access_denied + Gitlab::SlashCommands::Presenters::Access.new.generic_access_denied + end + + def create_note(issue:, note:) + note_params = { noteable: issue, note: note } + + Notes::CreateService.new(project, current_user, note_params).execute + end + + def presenter(note) + Gitlab::SlashCommands::Presenters::IssueComment.new(note) + end + end + end +end diff --git a/lib/gitlab/slash_commands/presenters/access.rb b/lib/gitlab/slash_commands/presenters/access.rb index 9ce1bcfb37c..fbc3cf2e049 100644 --- a/lib/gitlab/slash_commands/presenters/access.rb +++ b/lib/gitlab/slash_commands/presenters/access.rb @@ -15,6 +15,10 @@ module Gitlab MESSAGE end + def generic_access_denied + ephemeral_response(text: 'You are not allowed to perform the given chatops command.') + end + def deactivated ephemeral_response(text: <<~MESSAGE) You are not allowed to perform the given chatops command since diff --git a/lib/gitlab/slash_commands/presenters/issue_comment.rb b/lib/gitlab/slash_commands/presenters/issue_comment.rb new file mode 100644 index 00000000000..cce71e23b21 --- /dev/null +++ b/lib/gitlab/slash_commands/presenters/issue_comment.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module Gitlab + module SlashCommands + module Presenters + class IssueComment < Presenters::Base + include Presenters::NoteBase + + def present + ephemeral_response(new_note) + end + + private + + def new_note + { + attachments: [ + { + title: "#{issue.title} · #{issue.to_reference}", + title_link: resource_url, + author_name: author.name, + author_icon: author.avatar_url, + fallback: "New comment on #{issue.to_reference}: #{issue.title}", + pretext: pretext, + color: color, + fields: fields, + mrkdwn_in: [ + :title, + :pretext, + :fields + ] + } + ] + } + end + + def pretext + "I commented on an issue on #{author_profile_link}'s behalf: *#{issue.to_reference}* in #{project_link}" + end + end + end + end +end diff --git a/lib/gitlab/slash_commands/presenters/note_base.rb b/lib/gitlab/slash_commands/presenters/note_base.rb new file mode 100644 index 00000000000..7758fc740de --- /dev/null +++ b/lib/gitlab/slash_commands/presenters/note_base.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module Gitlab + module SlashCommands + module Presenters + module NoteBase + GREEN = '#38ae67' + + def color + GREEN + end + + def issue + resource.noteable + end + + def project + issue.project + end + + def project_link + "[#{project.full_name}](#{project.web_url})" + end + + def author + resource.author + end + + def author_profile_link + "[#{author.to_reference}](#{url_for(author)})" + end + + def fields + [ + { + title: 'Comment', + value: resource.note + } + ] + end + + private + + attr_reader :resource + end + end + end +end diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index 30c9855507d..5dbdc8b2cdd 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -131,7 +131,8 @@ module Gitlab omniauth_enabled: Gitlab::Auth.omniauth_enabled?, prometheus_metrics_enabled: Gitlab::Metrics.prometheus_metrics_enabled?, reply_by_email_enabled: Gitlab::IncomingEmail.enabled?, - signup_enabled: Gitlab::CurrentSettings.allow_signup? + signup_enabled: Gitlab::CurrentSettings.allow_signup?, + web_ide_clientside_preview_enabled: Gitlab::CurrentSettings.web_ide_clientside_preview_enabled? } end diff --git a/lib/gitlab/usage_data_counters/web_ide_counter.rb b/lib/gitlab/usage_data_counters/web_ide_counter.rb index 0718c1dd761..c012a6c96df 100644 --- a/lib/gitlab/usage_data_counters/web_ide_counter.rb +++ b/lib/gitlab/usage_data_counters/web_ide_counter.rb @@ -8,6 +8,7 @@ module Gitlab COMMITS_COUNT_KEY = 'WEB_IDE_COMMITS_COUNT' MERGE_REQUEST_COUNT_KEY = 'WEB_IDE_MERGE_REQUESTS_COUNT' VIEWS_COUNT_KEY = 'WEB_IDE_VIEWS_COUNT' + PREVIEW_COUNT_KEY = 'WEB_IDE_PREVIEWS_COUNT' class << self def increment_commits_count @@ -34,11 +35,22 @@ module Gitlab total_count(VIEWS_COUNT_KEY) end + def increment_previews_count + return unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled? + + increment(PREVIEW_COUNT_KEY) + end + + def total_previews_count + total_count(PREVIEW_COUNT_KEY) + end + def totals { web_ide_commits: total_commits_count, web_ide_views: total_views_count, - web_ide_merge_requests: total_merge_requests_count + web_ide_merge_requests: total_merge_requests_count, + web_ide_previews: total_previews_count } end end diff --git a/spec/controllers/projects/usage_ping_controller_spec.rb b/spec/controllers/projects/usage_ping_controller_spec.rb new file mode 100644 index 00000000000..a9abbff160d --- /dev/null +++ b/spec/controllers/projects/usage_ping_controller_spec.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::UsagePingController do + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } + + describe 'POST #web_ide_clientside_preview' do + subject { post :web_ide_clientside_preview, params: { namespace_id: project.namespace, project_id: project } } + + before do + sign_in(user) if user + end + + context 'when web ide clientside preview is enabled' do + before do + stub_application_setting(web_ide_clientside_preview_enabled: true) + end + + context 'when the user is not authenticated' do + let(:user) { nil } + + it 'returns 302' do + subject + + expect(response).to have_gitlab_http_status(302) + end + end + + context 'when the user does not have access to the project' do + it 'returns 404' do + subject + + expect(response).to have_gitlab_http_status(404) + end + end + + context 'when the user has access to the project' do + let(:user) { project.owner } + + it 'increments the counter' do + expect do + subject + end.to change { Gitlab::UsageDataCounters::WebIdeCounter.total_previews_count }.by(1) + end + end + end + + context 'when web ide clientside preview is not enabled' do + let(:user) { project.owner } + + before do + stub_application_setting(web_ide_clientside_preview_enabled: false) + end + + it 'returns 404' do + subject + + expect(response).to have_gitlab_http_status(404) + end + end + end +end diff --git a/spec/frontend/ide/components/preview/clientside_spec.js b/spec/frontend/ide/components/preview/clientside_spec.js index a7c74dc992a..6a33f4998c5 100644 --- a/spec/frontend/ide/components/preview/clientside_spec.js +++ b/spec/frontend/ide/components/preview/clientside_spec.js @@ -24,6 +24,9 @@ describe('IDE clientside preview', () => { getFileData: jest.fn().mockReturnValue(Promise.resolve({})), getRawFileData: jest.fn().mockReturnValue(Promise.resolve('')), }; + const storeClientsideActions = { + pingUsage: jest.fn().mockReturnValue(Promise.resolve({})), + }; const waitForCalls = () => new Promise(setImmediate); @@ -42,6 +45,12 @@ describe('IDE clientside preview', () => { ...getters, }, actions: storeActions, + modules: { + clientside: { + namespaced: true, + actions: storeClientsideActions, + }, + }, }); wrapper = shallowMount(Clientside, { @@ -76,7 +85,8 @@ describe('IDE clientside preview', () => { describe('with main entry', () => { beforeEach(() => { createComponent({ getters: { packageJson: dummyPackageJson } }); - return wrapper.vm.initPreview(); + + return waitForCalls(); }); it('creates sandpack manager', () => { @@ -95,6 +105,10 @@ describe('IDE clientside preview', () => { }, ); }); + + it('pings usage', () => { + expect(storeClientsideActions.pingUsage).toHaveBeenCalledTimes(1); + }); }); describe('computed', () => { diff --git a/spec/frontend/ide/stores/modules/clientside/actions_spec.js b/spec/frontend/ide/stores/modules/clientside/actions_spec.js new file mode 100644 index 00000000000..a47bc0bd711 --- /dev/null +++ b/spec/frontend/ide/stores/modules/clientside/actions_spec.js @@ -0,0 +1,39 @@ +import MockAdapter from 'axios-mock-adapter'; +import testAction from 'helpers/vuex_action_helper'; +import { TEST_HOST } from 'helpers/test_constants'; +import axios from '~/lib/utils/axios_utils'; +import * as actions from '~/ide/stores/modules/clientside/actions'; + +const TEST_PROJECT_URL = `${TEST_HOST}/lorem/ipsum`; +const TEST_USAGE_URL = `${TEST_PROJECT_URL}/usage_ping/web_ide_clientside_preview`; + +describe('IDE store module clientside actions', () => { + let rootGetters; + let mock; + + beforeEach(() => { + rootGetters = { + currentProject: { + web_url: TEST_PROJECT_URL, + }, + }; + mock = new MockAdapter(axios); + }); + + afterEach(() => { + mock.restore(); + }); + + describe('pingUsage', () => { + it('posts to usage endpoint', done => { + const usageSpy = jest.fn(() => [200]); + + mock.onPost(TEST_USAGE_URL).reply(() => usageSpy()); + + testAction(actions.pingUsage, null, rootGetters, [], [], () => { + expect(usageSpy).toHaveBeenCalled(); + done(); + }); + }); + }); +}); diff --git a/spec/lib/gitlab/slash_commands/command_spec.rb b/spec/lib/gitlab/slash_commands/command_spec.rb index dc412c80e68..5a8c721a634 100644 --- a/spec/lib/gitlab/slash_commands/command_spec.rb +++ b/spec/lib/gitlab/slash_commands/command_spec.rb @@ -115,5 +115,10 @@ describe Gitlab::SlashCommands::Command do let(:params) { { text: 'issue move #78291 to gitlab/gitlab-ci' } } it { is_expected.to eq(Gitlab::SlashCommands::IssueMove) } end + + context 'IssueComment is triggered' do + let(:params) { { text: "issue comment #503\ncomment body" } } + it { is_expected.to eq(Gitlab::SlashCommands::IssueComment) } + end end end diff --git a/spec/lib/gitlab/slash_commands/issue_comment_spec.rb b/spec/lib/gitlab/slash_commands/issue_comment_spec.rb new file mode 100644 index 00000000000..c6f56d10d1f --- /dev/null +++ b/spec/lib/gitlab/slash_commands/issue_comment_spec.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::SlashCommands::IssueComment do + describe '#execute' do + let(:project) { create(:project, :public) } + let(:issue) { create(:issue, project: project) } + let(:user) { issue.author } + let(:chat_name) { double(:chat_name, user: user) } + let(:regex_match) { described_class.match("issue comment #{issue.iid}\nComment body") } + + subject { described_class.new(project, chat_name).execute(regex_match) } + + context 'when the issue exists' do + context 'when project is private' do + let(:project) { create(:project) } + + context 'when the user is not a member of the project' do + let(:chat_name) { double(:chat_name, user: create(:user)) } + + it 'does not allow the user to comment' do + expect(subject[:response_type]).to be(:ephemeral) + expect(subject[:text]).to match('not found') + expect(issue.reload.notes.count).to be_zero + end + end + end + + context 'when the user is not a member of the project' do + let(:chat_name) { double(:chat_name, user: create(:user)) } + + context 'when the discussion is locked in the issue' do + before do + issue.update!(discussion_locked: true) + end + + it 'does not allow the user to comment' do + expect(subject[:response_type]).to be(:ephemeral) + expect(subject[:text]).to match('You are not allowed') + expect(issue.reload.notes.count).to be_zero + end + end + end + + context 'when the user can comment on the issue' do + context 'when comment body exists' do + it 'creates a new comment' do + expect { subject }.to change { issue.notes.count }.by(1) + end + + it 'a new comment has a correct body' do + subject + + expect(issue.notes.last.note).to eq('Comment body') + end + end + + context 'when comment body does not exist' do + let(:regex_match) { described_class.match("issue comment #{issue.iid}") } + + it 'does not create a new comment' do + expect { subject }.not_to change { issue.notes.count } + end + + it 'displays the errors' do + expect(subject[:response_type]).to be(:ephemeral) + expect(subject[:text]).to match("- Note can't be blank") + end + end + end + end + + context 'when the issue does not exist' do + let(:regex_match) { described_class.match("issue comment 2343242\nComment body") } + + it 'returns not found' do + expect(subject[:response_type]).to be(:ephemeral) + expect(subject[:text]).to match('not found') + end + end + end + + describe '.match' do + subject(:match) { described_class.match(command) } + + context 'when a command has an issue ID' do + context 'when command has a comment body' do + let(:command) { "issue comment 503\nComment body" } + + it 'matches an issue ID' do + expect(match[:iid]).to eq('503') + end + + it 'matches an note body' do + expect(match[:note_body]).to eq('Comment body') + end + end + end + + context 'when a command has a reference prefix for issue ID' do + let(:command) { "issue comment #503\nComment body" } + + it 'matches an issue ID' do + expect(match[:iid]).to eq('503') + end + end + + context 'when a command does not have an issue ID' do + let(:command) { 'issue comment' } + + it 'does not match' do + is_expected.to be_nil + end + end + end +end diff --git a/spec/lib/gitlab/slash_commands/presenters/access_spec.rb b/spec/lib/gitlab/slash_commands/presenters/access_spec.rb index c7b83467660..804184a7173 100644 --- a/spec/lib/gitlab/slash_commands/presenters/access_spec.rb +++ b/spec/lib/gitlab/slash_commands/presenters/access_spec.rb @@ -22,6 +22,16 @@ describe Gitlab::SlashCommands::Presenters::Access do end end + describe '#generic_access_denied' do + subject { described_class.new.generic_access_denied } + + it { is_expected.to be_a(Hash) } + + it_behaves_like 'displays an error message' do + let(:error_message) { 'You are not allowed to perform the given chatops command.' } + end + end + describe '#deactivated' do subject { described_class.new.deactivated } diff --git a/spec/lib/gitlab/slash_commands/presenters/issue_comment_spec.rb b/spec/lib/gitlab/slash_commands/presenters/issue_comment_spec.rb new file mode 100644 index 00000000000..b5ef417cb93 --- /dev/null +++ b/spec/lib/gitlab/slash_commands/presenters/issue_comment_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::SlashCommands::Presenters::IssueComment do + let_it_be(:project) { create(:project) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:note) { create(:note, project: project, noteable: issue) } + let(:author) { note.author } + + describe '#present' do + let(:attachment) { subject[:attachments].first } + subject { described_class.new(note).present } + + it { is_expected.to be_a(Hash) } + + it 'sets ephemeral response type' do + expect(subject[:response_type]).to be(:ephemeral) + end + + it 'sets the title' do + expect(attachment[:title]).to eq("#{issue.title} · #{issue.to_reference}") + end + + it 'sets the fallback text' do + expect(attachment[:fallback]).to eq("New comment on #{issue.to_reference}: #{issue.title}") + end + + it 'sets the fields' do + expect(attachment[:fields]).to eq([{ title: 'Comment', value: note.note }]) + end + + it 'sets the color' do + expect(attachment[:color]).to eq('#38ae67') + end + end +end diff --git a/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb index 7a01f7d1de8..96ebeb8ff76 100644 --- a/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb +++ b/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb @@ -34,22 +34,54 @@ describe Gitlab::UsageDataCounters::WebIdeCounter, :clean_gitlab_redis_shared_st it_behaves_like 'counter examples' end + describe 'previews counter' do + let(:setting_enabled) { true } + + before do + stub_application_setting(web_ide_clientside_preview_enabled: setting_enabled) + end + + context 'when web ide clientside preview is enabled' do + let(:increment_counter_method) { :increment_previews_count } + let(:total_counter_method) { :total_previews_count } + + it_behaves_like 'counter examples' + end + + context 'when web ide clientside preview is not enabled' do + let(:setting_enabled) { false } + + it 'does not increment the counter' do + expect(described_class.total_previews_count).to eq(0) + + 2.times { described_class.increment_previews_count } + + expect(described_class.total_previews_count).to eq(0) + end + end + end + describe '.totals' do commits = 5 merge_requests = 3 views = 2 + previews = 4 before do + stub_application_setting(web_ide_clientside_preview_enabled: true) + commits.times { described_class.increment_commits_count } merge_requests.times { described_class.increment_merge_requests_count } views.times { described_class.increment_views_count } + previews.times { described_class.increment_previews_count } end it 'can report all totals' do expect(described_class.totals).to include( web_ide_commits: commits, web_ide_views: views, - web_ide_merge_requests: merge_requests + web_ide_merge_requests: merge_requests, + web_ide_previews: previews ) end end diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index b0886963a04..0ad196bd050 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -76,6 +76,7 @@ describe Gitlab::UsageData do avg_cycle_analytics influxdb_metrics_enabled prometheus_metrics_enabled + web_ide_clientside_preview_enabled )) end @@ -93,6 +94,7 @@ describe Gitlab::UsageData do web_ide_views web_ide_commits web_ide_merge_requests + web_ide_previews navbar_searches cycle_analytics_views productivity_analytics_views @@ -252,6 +254,7 @@ describe Gitlab::UsageData do expect(subject[:container_registry_enabled]).to eq(Gitlab.config.registry.enabled) expect(subject[:dependency_proxy_enabled]).to eq(Gitlab.config.dependency_proxy.enabled) expect(subject[:gitlab_shared_runners_enabled]).to eq(Gitlab.config.gitlab_ci.shared_runners_enabled) + expect(subject[:web_ide_clientside_preview_enabled]).to eq(Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?) end end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 1e06d0fd7b9..c93e6aafd75 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -281,6 +281,44 @@ describe Namespace do end end + shared_examples 'move_dir without repository storage feature' do |storage_version| + let(:namespace) { create(:namespace) } + let(:gitlab_shell) { namespace.gitlab_shell } + let!(:project) { create(:project_empty_repo, namespace: namespace, storage_version: storage_version) } + + it 'calls namespace service' do + expect(gitlab_shell).to receive(:add_namespace).and_return(true) + expect(gitlab_shell).to receive(:mv_namespace).and_return(true) + + namespace.move_dir + end + end + + shared_examples 'move_dir with repository storage feature' do |storage_version| + let(:namespace) { create(:namespace) } + let(:gitlab_shell) { namespace.gitlab_shell } + let!(:project) { create(:project_empty_repo, namespace: namespace, storage_version: storage_version) } + + it 'does not call namespace service' do + expect(gitlab_shell).not_to receive(:add_namespace) + expect(gitlab_shell).not_to receive(:mv_namespace) + + namespace.move_dir + end + end + + context 'project is without repository storage feature' do + [nil, 0].each do |storage_version| + it_behaves_like 'move_dir without repository storage feature', storage_version + end + end + + context 'project has repository storage feature' do + [1, 2].each do |storage_version| + it_behaves_like 'move_dir with repository storage feature', storage_version + end + end + context 'with subgroups' do let(:parent) { create(:group, name: 'parent', path: 'parent') } let(:new_parent) { create(:group, name: 'new_parent', path: 'new_parent') } diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 28778bf26d4..561c2b572ec 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -788,4 +788,10 @@ describe 'project routing' do expect(put("/gitlab/gitlabhq/-/deploy_tokens/1/revoke")).to route_to("projects/deploy_tokens#revoke", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') end end + + describe Projects::UsagePingController, 'routing' do + it 'routes to usage_ping#web_ide_clientside_preview' do + expect(post('/gitlab/gitlabhq/usage_ping/web_ide_clientside_preview')).to route_to('projects/usage_ping#web_ide_clientside_preview', namespace_id: 'gitlab', project_id: 'gitlabhq') + end + end end |